I have a class with method save():
public class FilesystemImagePersistenceStrategy implements ImagePersistenceStrategy {
public void save(MultipartFile file, Image image) {
File dest = createFile(image);
writeToFile(file, dest);
}
// protected to allow spying
protected void writeToFile(MultipartFile file, File dest) throws IOException {
IOUtils.copy(file.getInputStream(), new FileOutputStream(dest));
}
}
And now I want to check name of the file before it will be saved:
class FilesystemImagePersistenceStrategyTest extends Specification {
private ImagePersistenceStrategy strategy = Spy(FilesystemImagePersistenceStrategy)
private MultipartFile multipartFile = Mock()
private Image image = TestObjects.createImage()
def "save() should gives proper name to the file"() {
given:
String expectedFileName = ...
when:
strategy.save(multipartFile, image)
then:
1 * strategy.writeToFile({ MultipartFile file, File dest ->
assert dest.name == expectedFileName
return true
})
}
}
But unfortunately it doesn't work, real method invoked instead...
Why it so? And how to check method's argument?
P.S. I also provided an example at http://meetspock.appspot.com/script/5741031244955648
I ended up with the following:
1 * strategy.writeToFile(
multipartFile,
{ assert it.name == expectedFileName; return true }
) >> {}
There assert call needs to show me nice error message, like this:
it.name != expectedFileName
| | | |
| 1.png| 2.png
| false
/tmp/1.png
Also return true is required for case when test fails. Without this statement closure will return false and this method will not be accounted as candidate (and real method will be executed).
The argument constraint specified for 1 * strategy.writeToFile is wrong. There needs to be one constraint per argument, and constraints must not contain assert statements. Additionally, if a spy is to be used as a partial mock, the default response (which calls through to the real method) needs to be suppressed by supplying a stubbed response ("do nothing" in this case). This leads to:
...
then:
1 * strategy.writeToFile(multipartFile, { it.name == expectedFileName }) >> {}
Which can be simplified to:
...
then:
1 * strategy.writeToFile(multipartFile, expectedFileName) >> {}
for multiplicity and assertions on mock, I used the following:
then:
numberOfCalls * mock.accept(_) >> {ArgType arg ->
assert arg.id == my.id
assert arg.minSerial == my.min()
assert arg.maxSerial == my.max()
}
Related
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");
}
}
I have a service that I'm trying to test. Inside this service is another UserAPIService that I want to mock. To mock it I'm doing the following:
given:
def userAPIServiceMock = mockFor(UserAPIService)
userAPIServiceMock.demand.createUser { def apiToken, firstname, lastname, email -> return true
}
service.userAPIService = userAPIServiceMock.createMock()
In the demand closure, I don't really care what arguments are passed to the createUser method. Is there a way I can say "regardless of the arguments passed to the createUser method, return true."
In other words, how can I change
userAPIServiceMock.demand.createUser { def apiToken, firstname, lastname, email -> return true
to
userAPIServiceMock.demand.createUser { [any arguments] -> return true
This is possible with Spock.
The syntax is as follows:
mock.method(*_) >> { args -> true }
Not sure how your Grails service needs to be mocked, but here's a full, general example in Spock:
interface Service {
boolean hej( String s, boolean b, char c )
}
class ExampleSpec extends Specification {
def "mock method with any number of args"() {
when:
def mock = Mock( Service )
mock.hej(*_) >> { args -> true }
then:
mock.hej( 'hi', true, 'a' as char ) == true
}
}
args is a List containing the actual arguments, which you can inspect in the closure and return the appropriate value.
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()
class ProjectDashBoardController {
/*
* This method is used to display project implementation's overview.
*/
def check() {
render "Hello"
}
and this is my integration test
package com.spock
import grails.plugin.spock.IntegrationSpec
class ProjectDashBoardControllerIntegrationSpec extends IntegrationSpec {
ProjectDashBoardController controller = new ProjectDashBoardController()
def cleanup() {
}
void "test check action"() {
when:
controller.check()
then:
controller.check()
assertEquals "/dashboard/index", controller.response.redirectedUrl
}
}
as per the, then condition the test should fail since action render but instead it showing such error
No signature of method: com.itxchg.ProjectDashBoardControllerIntegrationSpec.assertEquals() is applicable for argument types: (java.lang.String, null) values: [/dashboard/index, null]
Spock doesn't have an assertEquals method, you should use regular Groovy power asserts, although assert is implicit in then block when spock is used:
assert "/dashboard/index" == controller.response.redirectedUrl
In your case though you do have have a redirect scenario to test. What actually should be tested is that the response consists the rendered text:
void "test check action"() {
when:
controller.check()
then:
// Note there is no need to explicitly specify assert in then block
// Assertion is implicit
controller.response.text == "Hello"
}
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.