victorio
victorio

Reputation: 6646

How to set variables after an expected mock method call in THEN stage in Spock Groovy?

I want to test my Java service with Spock Groovy, and the service is a bit tricky, because a method call returns a value and also changes the content of the variable which was passed to the method.

Since I want to mock this method call, I need to tell Spock somehow that when the method was executed, return a specific value AND change the content of the passed variable.

Something like this:

given: "list with one element"
List<String> list = ["mock"]

when: "executing the service call"
service.execute(list)

then: "external method is called, which updates the passed variable and returns true as success"
1 * external.addOneMoreToList(list) >> true
and: "list is updated successfully"
list.size == 2
list.get(1) == "mock 2"

But I don't know where and how to update the list by adding the next element: "mock 2".

I know this example does not make sense, but I didn't want to write my real testcase, because it is huge, but I need similar ad-hoc-update

Upvotes: 1

Views: 2162

Answers (1)

Use a closure instead of a simple value for the interaction, like this:

1 * external.addOneMoreToList(list) >> { list ->
    list << 'mock 2'
    return true
}

A few idiomatic notes:

  • It's not actually necessary to return true in this case, since (assuming your return type is boolean) Groovy will consider the non-empty list truthy. It's still a good idea to be clear.

  • As in JUnit, expected values come first, then actual values (2 == list.size()).

  • You can index into a List with []: 'mock 2' == list[1].

  • It's a good idea whenever practical to use random values, such as for your 'mock 2' value, since this helps prevent accidental passes. You can set variables in your given block and use them in interactions; I typically use commons-lang3 RandomStringUtils.

And try to slim down your test case to whatever extent practical! Spock's friendly interaction mocking makes it much less painful to use test doubles for interfaces that are perhaps too complicated, and extended interactions can be a reasonable use case for @Stepwise (I've used it for Selenium tests with multi-step scenarios).

Upvotes: 2

Related Questions