I'm struggling to understand something about Spock interactions in a Groovy unit test.
I have the following types:
public interface Bar {
public String getMessage();
}
public class Foo {
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
public String getMessage() {
return bar.getMessage();
}
}
and I then wrote the following Groovy/Spock test:
class FooSpec extends Specification {
private Bar bar;
private Foo foo;
def setup() {
bar = Mock(Bar) { getMessage() >> "hello" }
foo = new Foo()
foo.bar = bar
}
def "say hello"() {
expect:
foo.message.equals("hello")
}
def "say goodbye"() {
setup:
bar.getMessage() >> "goodbye"
expect:
foo.message.equals("goodbye")
}
}
The code creates a mock Bar
instance in the setup, initializes Bar.getMessage()
to return hello
, and assigns this to a new Foo
instance.
The first test verifies that foo.getMessage()
is equal to hello
.
The second test tries to modify the bar
mock so that it's getMessage
method returns goodbye
. We then expect that foo.getMessage()
(which delegates to bar.getMessage()
) would then return goodbye
. However the test fails as follows:
FooSpec:say goodbye:26 Condition not satisfied
because foo.message
is still equal to hello
.
I also tried the following:
def "say goodbye"() {
when:
bar.getMessage() >> "goodbye"
then:
foo.message.equals("goodbye")
}
and:
def "say goodbye"() {
when:
no_op()
then:
bar.getMessage() >> "goodbye"
foo.message.equals("goodbye")
}
But both failed with the same hello does not equal goodbye message.
I'm probably still thinking in Mockito mode, and assume that an interaction is the equivalent of a when(...).thenReturn(...)
expression, and that later interactions would override earlier interactions.
Is there a simple way using Spock to declare an interaction in a setup
method, then override that interaction in a test case? Or do I need to remove the setup()
method and basically add a setup:
block to each test case?
That's a tricky one. As stated in the docs, interactions declared in a then-block have precedence over interactions declared earlier. However, interactions declared in a then-block are scoped to the previous when-block. (This allows to have multiple when-then pairs.) Hence your last try doesn't work, but the following will:
def setup() {
bar.message >> "hello"
}
def "say goodbye"() {
when:
def msg = foo.message
then:
bar.message >> "goodbye"
msg == "goodbye"
}
I agree that it would be good for interactions declared in test methods to always override interactions declared in setup methods. Anyway, a good alternative to overriding interactions is for each test method to call a helper method that sets up the expected interactions for that test method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With