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.
Related
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.
How can you unit test a class that has a superclass in Spock that invokes method calls form its superclass? Or how do you mock a superclass in Spock?
Ex:
class Bar {
def method1(parm1){
//Method actions
}
}
class Foo extends Bar {
def method2(param1, param2) {
//Method actions
super.method1(param1)
}
}
How can I mock behavior of class Bar?
You might use your class Foo as a Spy. The spy will create an instance of your class Foo but gives you the possibility of mocking any public methods declared in your spies class hierarchy.
def fooInstance = Spy(Foo)
fooInstance.method1(_) >> 'return value'
The following code will help you to specify what methods are called actually.
setup:
def fooInstance = Spy(Foo)
when: "this try-catch block is debug code"
try {
// do something with Foo or Bar
}
catch (Exception e) {
}
then:
0 * fooInstance._
This site may be useful. -> Spock Mock Cheatsheet
If you are using Spock to test Kotlin classes, you need to make the superclass methods open so that Spock can stub them.
I'm trying to write a unit test for my filters, and I'm struggling to understand the demand for my mocked object. Here is a simple failing test:
void "test my sanity"() {
setup:
def vendorPayment = mockFor(Payment)
vendorPayment.demand.buyerId { -> 123}
def vp = vendorPayment.createMock()
//vp.buyerId=123
println "buyer id: ${vp.buyerId}"
when:
def a = "testing"
then:
vp.buyerId == 123
}
I wanted to mock the getter for buyerId. Using demand doesn't work, but if I create the mock and then set the buyer id (the commented line), the test will pass. Does demand not work with getters? Is it because the getter is implicitly/dynamically created?
Method getBuyerId has to be mocked. Groovy adds the accessor methods for you in compile time, so method on demand has to be mocked. Take this simple case:
class Payment {
Integer buyerId
}
Getter/Setter for Payment.groovy will be added when the class is converted to bytecode after compile. Corresponding test would look like:
void "test my power"() {
setup:
def vendorPayment = mockFor(Payment)
vendorPayment.demand.getBuyerId(1..2) { -> 123}
def vp = vendorPayment.createMock()
println "buyer id: ${vp.buyerId}"
expect:
vp.buyerId == 123
//This would fail for < 2.3.* because of this bug which is fixed in 2.4
//http://jira.grails.org/browse/GRAILS-11075
vendorPayment.verify() //null
}
Note the changes that was made:
getBuyerId method is mocked instead of the field buyerId
test demands that getBuyerId will be called 1 to 2 times (first while printing, second in then block). By default if nothing is specified, it assumes the method will be called once, which would fail in this case as getBuyerId is invoked twice.
We can also verify that the mock control did its job after the test is done
I have several different implementations of a trait that I would like to test, and the test only uses the method signatures of the trait, so it seems like I should be able to use parameterized tests. However, the specs2 website doesn't seem to describe a straightforward way of writing parameterized tests. The closest is how to "share examples" but you still need to write every combination of tests and tested code, where I want to be able to specify:
A. Tests
B. Classes to test
That can be specified separately, but will test the cartesian product of the two.
Also don't forget that you can use for loops:
class MySpecification extends mutable.Specification {
Seq(new Foo, new Bar) foreach { tested =>
"it should do this" >> { tested must doThis }
"it should do that" >> { tested must doThat }
}
}
Write some thing like:
trait TraitTest extends Specification {
val thingWithTrait: TraitWithVariousImplementations
//TESTS GO HERE
}
class TestFoo extends TraitTest {
val thingWithTrait = new Foo
}
class TestBar extends TraitTest {
val thingWithTrait = new Bar
}