Closed xnslong closed 9 years ago
There are good reasons why things work this way (see history of related discussions on the mailing list). The only mocking framework with different semantics that I'm aware of in the Java world is Mockito. If you prefer Mockito's semantics (which have their own tradeoffs), you can use Mockito together with Spock. To always return result
, you'll need to add >> result
to both interactions.
There is a third way, which I usually choose when I want to verify the arguments. Instead of using the arguments matcher to verify the argument, you can use the return closure since it also as access to the arguments. This way you get an assertion error if the argument did not match your expectations.
then:
1 * underlyingService.sampleMethod(_) >> { args ->
assert args[0].bar == expectedBar
result
}
Thank you very much, @leonard84 @pniederw . The advice is really beneficial to me.
@pniederw Where can I check out the discussions on mail list? I'm interested in the reasons, but I didn't find where are the discussions. Is https://code.google.com/p/spock/issues/list the discussions history you mentioned?
Checkout the mailinglist https://groups.google.com/forum/#!forum/spockframework
I made some changes with a method, so I want to test the logic of this change. But I just feel it difficult to write a test function that reads clearly enough to explain my expectation. The problem is as following.
The method I am testing is
foo(input)
, which will call an underlying methodunderlyingService.sampleMethod(argObject): Result
. The changes I made will affect theargObject
passed from thefoo
method, and what I want to test is just the logic withargObject
. I'm not concerned with the returnedResult
object or any other conditions, if only they could be proper enough to avoid any unrelated exceptions.So I mocked a
Result
object, and it should be returned for any invocation of thesampleMethod
(because thefoo
method expects a non-nullResult
object from thesampleMethod
). And when thefoo
method is called, I should verify it that theargObject
passed from thefoo
method is just as expected. Finally, I wrote the following code that reluctantly meets the test requirement.The test function will work well when the
foo
method is correctly implemented; but when not implemented correctly, it will report some unexpected failure information (the information I want it to show is that "argument is not as expected", but it will showNullPointerException
about theresult
object in thefoo
method invocation; because the mockedsampleMethod
is not matched, so a defaultResult
object (null
) will be returned, which is unexpected by thefoo
method).Another important problem is that the
sampleMethod
in thethen:
clause (officially called "block", but maybe "clause" will be a better word, so I take it.) plays the role of Mocking and Verification at the same time. This is very confusing, because we will always think it that verifications and conclusions should be in thethen:
clause, but prerequisites should not. The prerequisites should be set in thesetup:
clause (of course, verifications should not be declared here in thesetup:
clause). So the ideal test code that will express my wish is like the following. But it always showsNullPointerException
whether thefoo
method is implemented correctly or not. The reason of this is that the declaration in thethen:
clause will be matched when the method is invoked, not the declaration in thesetup:
clause; the declaration in thethen:
clause defined noResult
, so the result returned to thefoo
method will benull
.That's all of my problem. I just wonder if there is any other way of writing the code that will satisfy my test requirement, or if we can have a discussion over the issue?