Spock verifying an exception thrown by mock together with mock interaction
Asked Answered
S

1

11

The problem I encountered is when I try to verify in the then block that an exception has been thrown, and that call on a mock has been made.

Look at the setup below:

class B {
    def b(A a) {
        a.a()
    }
}

class A {
    def a() {
    }
}

def "foo"() {
    given:
    def a = Mock(A)
    a.a() >> { throw new RuntimeException() }
    B b = new B()

    when:
    b.b(a)

    then:
    thrown(RuntimeException)
    1 * a.a()
}

The above test fails with message: Expected exception java.lang.RuntimeException, but no exception was thrown, but the code setting up the mock explicitly throws the exception.

Funny enough, if you remove the last line: 1 * a.a() the test passes. I didn't have similar problem when putting together another assertions in the then block which don't verify exceptions.

Any ideas what's going on?

Sungkiang answered 30/4, 2015 at 11:44 Comment(2)
While @Opal's answer is correct I'd question why this is a good idea. Generally (certainly not in all cases but many) you only need to verify an interaction occurs when the method in question has no direct effect on the code under test. A method that returns a value or throws an exception does.Walkway
The code from the question was inspired by a real case in which I wanted to verify that a method writing to a database is called, and if an error is thrown, it is propagated. There could be more reasons for that particular exception, so I needed to verify that the interaction with the mock is the reason for it.Sungkiang
C
18

It should be configured and verified in the following way:

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {
    def "foo"() {
        given:
        def a = Mock(A)
        B b = new B()

        when:
        b.b(a)

        then:
        thrown(RuntimeException)
        1 * a.a() >> { throw new RuntimeException() }
    }
}


class B {
    def b(A a) {
        a.a()
    }
}

class A {
    def a() {
    }
}

If you both mock and verify interactions mock behavior should be configured in where/then block.

Cribbage answered 30/4, 2015 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.