How to do argument capture with spock framework? - spock

I have some Java stuff like this:
public interface EventBus{
void fireEvent(GwtEvent<?> event);
}
public class SaveCommentEvent extends GwtEvent<?>{
private finalComment oldComment;
private final Comment newComment;
public SaveCommentEvent(Comment oldComment,Comment newComment){
this.oldComment=oldComment;
this.newComment=newComment;
}
public Comment getOldComment(){...}
public Comment getNewComment(){...}
}
and test code like this:
def "...."(){
EventBus eventBus=Mock()
Comment oldComment=Mock()
Comment newCommnet=Mock()
when:
eventBus.fireEvent(new SaveCommentEvent(oldComment,newComment))
then:
1*eventBus.fireEvent(
{
it.source.getClass()==SaveCommentEvent;
it.oldComment==oldComment;
it.newComment==newComment
}
)
}
I want to verify that the eventBus.fireEvent(..) gets called once with an Event with type SaveCommentEvent and construction parameters oldComment and newComment.
Code runs without errors but problem is:
After changing closure stuff from
{
it.source.getClass()==SaveCommentEvent;
it.oldComment==oldComment; //old==old
it.newComment==newComment //new==new
}
To
{
it.source.getClass()==Other_Class_Literal;
it.oldComment==newComment; //old==new
it.newComment==oldComment //new==old
}
Still, code runs without error? Apparently the closure didn't do what I want, so the question is: How to do argument capturing?

I got it:
SaveCommentEvent firedEvent
given:
...
when:
....
then:
1 * eventBus.fireEvent(_) >> {arguments -> firedEvent=arguments[0]}
firedEvent instanceof SaveModelEvent
firedEvent.newModel == newModel
firedEvent.oldModel == oldModel

then:
1*eventBus.fireEvent(
{
it.source.getClass()==SaveCommentEvent;
it.oldComment==oldComment;
it.newComment==newComment
}
)
In your code it is a Groovy Closure Implicit Variable reference to a mock eventBus Interface which has no fields. How could you verify them?
Also, I think the order of events that has to happen to use Spock Mocks is not necessarily intuitive. I would write it up here except it would not be as good as Kenneth Kousen's explanation.

Same idea with #Alex Luya but put the assertions in the closure and use assert on each of them. cf. Spock Framework Reference Documentation.
then:
1 * eventBus.fireEvent(_) >> {
def firedEvent = it[0]
assert firedEvent instanceof SaveModelEvent
assert firedEvent.newModel == newModel
assert firedEvent.oldModel == oldModel
}

In 2021 (7 yrs later) it is possible to do the following with groovy (2.5):
...
then:
1 * eventBus.fireEvent(_) >> { SaveModelEvent event ->
assert event.newModel == newModel
assert event.oldModel == oldModel
}
0 * _
.. which feels more handy to me and saves a line or two. :)

If you want to mock a method's response and also verify the same method's params(same as capturing the params), you can use Spock's code constraints (among other constraints) to partially match params, and at the same time, verify the method params. :
1 * list.add({
verifyAll(it, Person) {
firstname == 'William'
lastname == 'Kirk'
age == 45
}
}) >> mockedResponse
PS: Solution inspired by this response from #Leonard Brünings

In the answer from #alex-luya above, I found that the variable firedEvent needs the #Shared annotation.
Then I can capture the value and run my checks on the value outside the closure.

Related

Spock testing: Too many invocation

I wrote service for manual requeuing events from one queue to another.
public class ReQueueService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
InfoLog infoLog;
while (rabbitTemplate != null &&
(infoLog = (InfoLog) rabbitTemplate.receiveAndConvert(EVENT_WAITING_FOR_REQUEUE)) != null
) {
rabbitTemplate.convertAndSend(SOME_QUEUE, infoLog.getSomeEvent());
}
}
}
The problem I am facing is getting:
Too many invocations for:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
} (2 invocations)
Matching invocations (ordered by last occurrence):
2 * rabbitTemplate.convertAndSend(SOME_QUEUE, ...
while my code in test looks like this:
class ReQueueServiceTest extends Specification {
def "should resend single event to some queue" () {
given:
InfoLog infoLog = Fixtures.createInfoLog()
def rabbitTemplate = Mock(RabbitTemplate){
receiveAndConvert(EVENT_WAITING_FOR_REQUEUE) >> { infoLog }
}
ReQueueService reSyncService = new ReQueueService(rabbitTemplate)
when:
reSyncService.retry()
then:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
}
}
}
The question is why I have 2 invocations, if I stubb only one event?
EDIT:
link to repo with example: https://gitlab.com/bartekwichowski/spock-too-many
Thanks for the repo link. As soon as I could run the test and inspect the behaviour live, it was pretty easy to find out what was wrong. First I will make an educated guess about what you actually want to test:
The mock's receiveAndConvert method should return str when it is called first and then null when called again.
Subsequently you want to verify that the while loop runs exactly 1 iteration, i.e. that convertAndSend is called with exactly the parameters you expect.
This can be achieved by
receiveAndConvert("FOO") >>> [str, null]
1 * rabbitTemplate.convertAndSend("BAR", str) (no need for ugly assertions inside a stubbed method, the parameters are verified against your parameter constraints already)
If I refactor your specification a little bit for prettier variable names and less verbosity, it looks like this:
class ReSyncServiceTest extends Specification {
def "should resend single event to resource sync queue"() {
given:
def message = "someValue"
def rabbitTemplate = Mock(RabbitTemplate) {
receiveAndConvert("FOO") >>> [message, null]
}
when:
new ReSyncService(rabbitTemplate).retry()
then:
1 * rabbitTemplate.convertAndSend("BAR", message)
}
}
P.S.: Your version with the assertion inside does not return anything explicitly, but implicitly the result of the last assertion. Be careful with that. With >> { ... } you are stubbing the method result! It would always return true in the version you have in Git and the test only terminates because you added the 1 * limit. If it was not there, you would have an endless loop. Your code did not do what you thought it did. Maybe the Spock manual can help you there. :-)
P.P.S.: Maybe you want to refactor your application code to be a bit easier to understand and maintain and to be a little less "smart". Also there is no need to check that rabbitTemplate != null in every iteration, once should be enough. How about this?
#Slf4j
#Service
#AllArgsConstructor
public class ReSyncService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
if (rabbitTemplate == null)
return;
String event;
while (null != (event = getEventFromQueue()))
rabbitTemplate.convertAndSend("BAR", event);
}
protected String getEventFromQueue() {
return (String) rabbitTemplate.receiveAndConvert("FOO");
}
}

Spock bug? callRealMethod() on stub does not throw expected exception

Extract from class CUT under test:
def compileOutputLines( TopDocs topDocs ) {
println "gubbins"
}
Test code:
def "my feature"(){
given:
CUT stubCut = Stub( CUT ){
compileOutputLines(_) >> { TopDocs mockTD ->
// NB no Exception is thrown
// try {
println "babbles"
callRealMethod()
println "bubbles"
// }catch( Exception e ) {
// println "exception $e"
// }
}
}
CUT spyCut = Spy( CUT ){
compileOutputLines(_) >> { TopDocs mockTD ->
println "babbles 2"
callRealMethod()
println "bubbles 2"
}
}
when:
stubCut.compileOutputLines( Mock( TopDocs ))
spyCut.compileOutputLines( Mock( TopDocs ))
then:
true
}
Output to stdout:
babbles
bubbles
babbles 2
gubbins
bubbles 2
I tried to find a link online to the full Spock Framework Javadoc... but I couldn't find it... the "non-framework" Javadoc is here, but you won't find the method callRealMethod in the index.
From the Javadoc API I have generated locally from the source, I can indeed find this method: it is a method of org.spockframework.mock.IMockInvocation. It says:
java.lang.Object callRealMethod()
Delegates this method invocation to the real object underlying this
mock object, including any method arguments. If this mock object has
no underlying real object, a CannotInvokeRealMethodException is
thrown.
Returns:
the return value of the method to which this invocation was delegated
My understanding (such as it is) is that a Stub should cause this Exception to be thrown. But it doesn't appear to be. Any comment from a passing expert?
Preface
This is an interesting question. In theory my answer would be:
callRealMethod() is only available for spies, not for mocks or stubs. It is also only mentioned in the chapter about spies, did you notice?
Think about it: A spy wraps a real object, so there you have a reference to a real method you can call. The same is not true for mocks and stubs which are just no-op subclasses. If you could call a real method for a stub, it would be a spy.
The puzzle
In reality I am seeing a different, even weirder behaviour from yours in my own test with Spock 1.1 (Groovy 2.4): No matter if I use a mock, stub or spy, callRealMethod() always calls the real method. This is really a surprise. So, yes, the behaviour is different from what I would have expected. Looking through the interface implementation's source code while debugging, I also cannot see any checks for the type of mock object (is it a spy or not?). The real method is just identified and called.
The solution
Looking at class DynamicProxyMockInterceptorAdapter I found the explanation for this behaviour: The exception mentioned in the IMockInvocation Javadoc is only thrown when trying to call the real method for an interface type mock, never for mocks or class type objects:
public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {
IResponseGenerator realMethodInvoker = (ReflectionUtil.isDefault(method) || ReflectionUtil.isObjectMethod(method))
? new DefaultMethodInvoker(target, method, arguments)
: new FailingRealMethodInvoker("Cannot invoke real method '" + method.getName() + "' on interface based mock object");
return interceptor.intercept(target, method, arguments, realMethodInvoker);
}
So the sentence "if this mock object has no underlying real object, a (...)Exception is thrown" is in essence correct, but ambiguous because it does not explain what "underlying real object" means. Your assumption was just wrong, so was mine. Lesson learned for both of us.
Now when would you see the described behaviour?
package de.scrum_master.stackoverflow;
public interface MyInterface {
void doSomething();
}
package de.scrum_master.stackoverflow
import org.spockframework.mock.CannotInvokeRealMethodException
import spock.lang.Specification
class MyInterfaceTest extends Specification {
def "Try to call real method on interface mock"() {
given:
MyInterface myInterface = Mock() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
def "Try to call real method on interface stub"() {
given:
MyInterface myInterface = Stub() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
def "Try to call real method on interface spy"() {
given:
MyInterface myInterface = Spy() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
}
Update: I have just created issue #830 requesting improvements in Spock's documentation.

Spock - test fails after interaction testing

This test works only when condition is tested. When mixed with interaction testing, it fails.
class Test extends Specification {
class Inner {
public String greet() {
return "hello"
}
}
def "simple test"() {
given:
def inner = Mock(Inner)
inner.greet() >> { "hi" }
when:
def msg = inner.greet()
then:
1 * inner.greet() // Below will pass when this line commented out.
msg == "hi"
}
}
The test will pass when interaction testing is removed.
Condition not satisfied:
msg == "hi"
| |
| false
null
It should be:
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
class Inner {
public String greet() {
return "hello"
}
}
def "simple test"() {
given:
def inner = Mock(Inner)
when:
def msg = inner.greet()
then:
1 * inner.greet() >> "hi"
msg == "hi"
}
}
Let's talk a bit about what's going on. (Or if you don't want to, read the "Scope of Interactions" section.)
What's happening is an issue of scoping. As you may know, you can have multiple sequential when/then pairs; any Mocking done in a then block is actually scoped to only its when block. What happens if the Mocked method was already defined outside the when/then scoping? The Mock defined in the then block takes precedence.
Congratulations! You've stumbled across the only way to overwrite established Mocked values/methods. I spent a long time figuring out how this worked before the new documentation was released.
So we know you're overwriting your mock that defines a value to return. How do we proceed from here?
given:
def inner = Mock(Inner)
1 * inner.greet() >> message
expect:
"hi" = inner.greet()
where:
message = "hi"
Parting thought... I hope you're not testing a value that you set within your test. That's effectively asserting 1 == 1. If you want to test your actual code while testing behavior I'd suggest using a Spy
given:
def inner = Spy(Inner)
1 * inner.greet() >> {
callRealMethod() // Actual method, read the documentation I linked
}
expect:
"hi" = inner.greet()

Grails mock same method many times with different result

I want to mock a object method that is called many times, and each times the result must be different.
Here what I'm trying to do:
fooMock.demand.someMethod(3..3) { ->
//call1
if (**some condition**)
return 1
//call2
if (**some condition**)
return 2
//call3
if (**some condition**)
return 3
}
So, is there a way to know what is the current call number ? or do you offers something better ?
It will be possible to do that in Grails 2.3-M2 (http://jira.grails.org/browse/GRAILS-4611) but until then, did someone has a workaround ?
You can create an attribute in your test to control that:
class MyTest {
int someMethodCount
#Before
void setup() {
fooMock.demand.someMethod(3..3) { ->
someMethodCount++
...
}
}
}
If you do not care about strict mocking and are only unit testing someMethod then you can use the primitive methodology of using maps:
void testSomething() {
def mockUtil = ["someMethod" : {param->
//I have used param only to handle conditional logics
//param can be optional
if(param == 1)return "John"
if(param == 2)return "Nancy"
if(param == 3)return "Mark"
}]
assert mockUtil.someMethod(1) == "John"
assert mockUtil.someMethod(2) == "Nancy"
assert mockUtil.someMethod(3) == "Mark"
}

Groovy Meta Programming

I want to override a method definition in Grails. I am trying to use Groovy metaprogramming as the class which I want to override belongs to a framework.
Below is the original class.
class SpringSocialSimpleSignInAdapter implements SignInAdapter {
private RequestCache requestCache
SpringSocialSimpleSignInAdapter(RequestCache requestCache) {
this.requestCache = requestCache;
}
String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
SignInUtils.signin localUserId
extractOriginalUrl request
}
}
I am trying to override like below
SpringSocialSimpleSignInAdapter.metaClass.signIn = {java.lang.String str, org.springframework.social.connect.Connection conn, org.springframework.web.context.request.NativeWebRequest webreq ->
println 'coming here....' // my implementation here
return 'something'
}
But for some reason overriding is not hapening. I am not able to figure it out. Any help would be greatly appretiated.
Thanks
Yeah, seems like that bug. I don't know your whole scenario, but anyway, here's a small workaround i made:
In your class definition, you don't implement the interface
You create your object and do your metamagic
Use groovy coercion to make it act as the interface and then you can pass it around
Here is a small script i made using JIRA bug to prove it:
interface I {
def doIt()
}
class T /*implements I*/ {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
// here the coercion happens and the assertion works fine
def i = t as I
assert !i.doIt()
assert !t.doIt()
// here the polymorphism happens fine
def iOnlyAcceptInterface(I i) { assert !i.doIt() }
iOnlyAcceptInterface(i)

Resources