I have a Spock test like this:
class SomeSpec extends Specification {
Map message
String topicArn = "aws::fake-sns-topic"
def 'test new message'() {
when: 'A new message is received'
message = [
"ownerToken": null,
"status": "NEW"
]
def response = api.doHandleRequest(message)
then: 'It is handled'
1 * snsClient.publish(topicArn, JsonOutput.toJson([
"ownerToken": null,
"status": "NEW"
]))
}
}
This works fine but I'd prefer to change the assertion to
1 * snsClient.publish(topicArn, message)
to reduce duplication of the map literal. When I do I get the following error:
Too few invocations for:
1 * snsClient.publish(topicArn, JsonOutput.toJson(message)) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * snsClient.publish('aws::fake-sns-topic', '{"ownerToken":null","status":"NEW"}')
One or more arguments(s) didn't match:
0: <matches>
1: argument == expected
| | |
| | null
| false
{"ownerToken":null,"status":"NEW"}
Why is the second argument coming through as null when I use the message variable instead of a map literal? The first argument is a variable rather than a literal and it is coming through fine.
I'd prefer to change the assertion to
1 * snsClient.publish(topicArn, message)
Well, it cannot work like that. As your posted test error implies, what you really want is
1 * snsClient.publish(topicArn, JsonOutput.toJson(message))
which leads to the exception you see during the test.
The reason is that the interaction you are testing in the then:
block must be prepared to be checked before the code in the when:
block gets executed. But before that block message
is null
. So you want to assign the value in a setup:
or given:
(both are just aliases for each other) block:
def 'new message gets published'() {
given: 'a new message'
message = [
"ownerToken": null,
"status" : "NEW"
]
when: 'the message is received'
def response = api.doHandleRequest(message)
then: 'it gets published'
1 * snsClient.publish(topicArn, JsonOutput.toJson(message))
}
Now your test passes.