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.
Related
I have an issue with creating test data with spock framework.
To follow "composition over inheritance", I have a class to create testdata for my unit tests. As a simple snipped it looks like this:
class TestData extends Specification{
Foo createFoo(){
GroovyMock(Foo){
doSomething() >> "MOCKED!"
}
}
}
When I write a Test, i like to test, if and how often the method has been invoked. Like this
def "simple test"(){
given:
TestData testData = new TestData()
Foo foo = testData.createFoo()
when:
println foo.doSomething()
then:
1 * foo.doSomething()
}
I know, this test doesn't makes sense. It's just for illustriating the behavior.
I would expect a "green result" of that test, since doSomething() has been invoked 1 time. But test result is red:
Too few invocations for:
1 * foo.doSomething() (0 invocations)
[...]
When i mock Foo directly, everything works fine :
def "simple test"(){
given:
Foo foo = GroovyMock(Foo){
doSomething() >> "MOCKED!"
}
when:
println foo.doSomething()
then:
1 * foo.doSomething()
}
Anyone has an idea how to treat this without deriving my testclass from TestData?
Btw. I used the stub returning "MOCKED!" to show, the mock works. But its not "overwritten" or whatever it is called, when testData created the mock.
Mocks interactions must be defined inside the Specification that uses them. Importing mocks from other sources like
TestData testData = new TestData()
Foo foo = testData.createFoo()
is not supported.
While it is possible to create mocks outside of a Specification and attach them later on, it is not possible to define interactions outside of a Specification.
So I have a method that looks something like this:
public Foo method() {
...
return service.get();
}
service is an external dependency of the class.
My test code:
Foo mockServiceResponse = Mockito.mock(Foo.class);
when(service.get()).thenReturn(mockServiceResponse);
In my unit test I inject a mock created with Mockito and set a when for service.get() so my question is, how do I test the return value of method?
If I just check if mockServiceResponse is equal to method() the test doesnt check much since if someone changes method to:
public Foo method() {
...
Foo f = service.get();
f.setId(null);
return f;
}
My test will still pass, which is obviously wrong, so how should I test this?
CLARIFICATION: What I want to test is that method doesnt change the object returned from service.get() (meaning, I want the second stub to fail my test), problem is mock objects just ignore methods called on them (like setId()) without failing the test.
You'll do something like:
Service service = mock(Service.class);
Foo aResponse = new Foo(1);
when(service.get()).thenReturn(aResponse);
MyClass subject = new MyClass(service);
Foo result = subject.method();
assertNull(result.getId());
You can use Mockito's verifyNoMoreInteractions or verifyZeroInteractions to assert that no calls were made to the service response object.
#Test
public void should_not_mutate_response() {
// given
Service mockService = Mockito.mock(Service.class);
Foo mockServiceResponse = Mockito.mock(Foo.class);
when(mockService.get()).thenReturn(mockServiceResponse);
SubjectUnderTest subjectUnderTest = new SubjectUnderTest(mockService);
// when
Foo result = subjectUnderTest.method();
//then
Mockito.verifyZeroInteractions(mockServiceResponse);
}
Or if you expect some particular interactions with the response object after all:
#Test
public void should_set_id_on_response() {
// given
...
// when
...
// then
Mockito.verify(mockServiceResponse).setId(ArgumentMatchers.anyInt());
Mockito.verifyNoMoreInteractions(mockServiceResponse);
}
We are in process of writing Unit test cases using Spock, I am not able to understand the following code snippet in then section varifying the declaration,
then:
1 * service.fraudMigrationOnboardingService.onboard(_) >>
{merchantId -> successCallBack.call(response)}
what is the meaning of the above code.
Because your question is lacking detail, I have to speculate and make an educated guess about your test. :-/
So you have a service with a member or getter fraudMigrationOnboardingService.
fraudMigrationOnboardingService has a method onboard taking a single parameter.
Obviously fraudMigrationOnboardingService is a mock or spy, which is why you can check interactions like 1 * ... on it.
The developer who wrote this test and whom, as it seems, you are too shy to ask about its meaning or who has left your company, wanted something specific to happen when method onboard(_) is called (probably by service) during the test: a call-back method call. Thus she declared the method stub { merchantId -> successCallBack.call(response) } as a replacement for what onboard(_) would normally do in this case. In a spy it would execute the original method, in a mock it would no nothing at all. But obviously that is not the desired behaviour, maybe because the test relies on different behavious later on.
In general, I think a test which is hard to read should be refactored, but anyway, here I am replicating your situation:
package de.scrum_master.stackoverflow
import spock.lang.Specification
class DummyTest extends Specification {
static class Service {
FraudMigrationOnboardingService fraudMigrationOnboardingService
void doSomething(String name) {
println "Doing something"
fraudMigrationOnboardingService.onboard(name)
}
}
static class FraudMigrationOnboardingService {
void onboard(String name) {
println "On-boarding $name"
}
}
static class SuccessCallBack {
void call(int httpResponse) {
println "Callback HTTP response = $httpResponse"
}
}
def "Some service test"() {
given:
def onboardingService = Mock(FraudMigrationOnboardingService)
def service = new Service(fraudMigrationOnboardingService: onboardingService)
def successCallBack = new SuccessCallBack()
def response = 200
when:
service.doSomething("ACME Inc.")
then:
1 * service.fraudMigrationOnboardingService.onboard(_) >>
{ merchantId -> successCallBack.call(response) }
}
}
The console log says:
Doing something
Callback HTTP response = 200
If you would comment out >> { merchantId -> successCallBack.call(response) }, it would only print
Doing something
for a mock and if you also change the Mock(FraudMigrationOnboardingService) into a Spy(FraudMigrationOnboardingService) it would print
Doing something
On-boarding ACME Inc.
Update: Maybe you still don't understand what the closure means, I am not sure. So I will explain it a bit more: As I said, it is just a stub for the onboard(String) method. The method parameter is mapped to merchantId but not used in the stubbed method. Instead the callback is triggered.
I have a simple class like
class SomeClass {
def foo() {
def bar= bar()
switch( bar ) {
return something based on format
}
}
def bar() {
return someValue
}
}
I've already written complete unit tests for the bar(). Now I need to write unit tests for foo() which is heavily dependant on the use of bar() method. I don't want to duplicate the setup phase as done for bar(), so I'd like to mock it by simply returning values I want.
I'm aware that Groovy supports this sort of "mocking" easily by simply defining it like SomeClass.property = "Hello World". Also, this can be done with collaborators as SomeClass.service = myMockedService. But I've not found a way to accomplish this with methods inside the unit under tests. Is there?
I tried with MockFor as in
def uut = new MockFor( SomeClass )
uut.demand.bar{ /* some values */ }
uut.use {
assert uut.foo() == expected
}
but it gives me
groovy.lang.MissingMethodException: No signature of method: groovy.mock.interceptor.MockFor.foo() is applicable for argument types: () values: []
UPDATE
In fact, I came up with a simple solution of using sub-classing. In the test method I create a subclass of SomeClass where I override the method I wish to mock/stub. After this, using an instance of the subclass gives me what I need.
This seems a bit rough, though. Any other suggestions on this?
If you want to mock the value returned by bar() for a single instance of SomeClass you can use metaprogramming. Try the following in the Groovy console:
class SomeClass {
def foo() {
}
def bar() {
return 'real value'
}
}
def uut = new SomeClass()
uut.metaClass.bar = {
return 'mock value'
}
assert 'mock value' == uut.bar()
If you want to mock bar() for all instances of SomeClass, replace this:
uut.metaClass.bar = {
return 'mock value'
}
with:
SomeClass.metaClass.bar = {
return 'mock value'
}
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.