I’ve been misunderstanding a fundamental issue of Spock Mocks. That’s annoying, but probably inevitable given that I work with so many state-of-the-art, evolving API’s. If you spend enough time on the bleeding edge, sooner or later you’ll get cut.
The problem is, though, I’ve been telling people something wrong for some time now, and that’s not acceptable. Thus this blog post. It’s one thing for me to make a mistake, but it’s quite another for me to mislead others. I want to fix that now. Besides, if I made the mistake, it’s also possible others are missing it, too.
I’m a big fan of the Spock testing framework. It’s very easy to learn, it works with both Java and Groovy systems, and it’s got a great mocking framework built into it. I’ve been a JUnit user for years, but I’ve never been able to commit to a mocking framework in Java. That’s partly because I still don’t find them particularly intuitive, and partly because I’m still not sure which one is going to win. I don’t want to commit to a framework (EasyMock? Mockito? PowerMock? etc) only to have to switch to a different one in a couple of years.
Spock is fun, though, and I use it whenever I can, and not just for the Star Trek related puns, some of which I’ll have to adopt here. Back in June, I wrote an article for NFJS the Magazine, entitled “Spock: I have been, and always shall be, your friendly testing framework.” I’m going to use an example from that article, with some variations, to show what I recently learned.
A basic Spock test
Here is part of a Groovy class called Tribble
that answers the question, “Do you know what you get when you feed a tribble too much?”:
[sourcecode language=”groovy”]
class Tribble {
def feed() {
def tribbles = [this]
10.times { tribbles << new Tribble() }
return tribbles
}
}
[/sourcecode]
The answer, of course, is a whole bunch of hungry little tribbles. The feed
method creates an ArrayList
of tribbles by starting with the current instance and then adding 10 more. I know the return
keyword isn’t strictly necessary, since closures automatically return their last evaluated value, but I use it sometimes for clear documentation. Groovy isn’t about writing the shortest code — it’s about writing the simplest, easiest to understand code that gets the job done.
To test this method, here’s a Spock test. It extends the spock.lang.Specification
class (which is required) and ends in the word “Spec” (which isn’t, but makes for a nice convention):
[sourcecode language=”groovy”]
import spock.lang.Specification
class TribbleSpec extends Specification {
Tribble tribble = new Tribble()
def "feed a tribble, get more tribbles"() {
when:
def result = tribble.feed()
then:
result.size() == 11
result.each {
it instanceof Tribble
}
}
}
[/sourcecode]
I never thought JUnit was verbose until I met Spock. For those who haven’t used it much, first let me say you have something fun to look forward to. That said, let me explain the test. Spock tests have a def
return type, then have a test name that describes what you’re trying to accomplish. The name is usually a short phrase, but it can be spread over several lines and even contain punctuation.
(Hamlet D’Arcy gives a great example in his blog post on Spock mocks, which is also echoed in the cool Spock Web Console. I also agree with him that Spock mocks should be called “smocks”, but since it doesn’t have a direct Star Trek association I’m not sure that will catch on.)
As Peter Niederweiser, the creator of the framework, points out, the method name becomes the body of an annotation, but that’s all under the hood.
The rest of the test consists of a when
and a then
block, representing a stimulus/response pair. The when
block contains the method invocation, and the then
block includes a series of boolean conditions that must be true for the test to pass. Nice and simple.
Tribbles do more than just eat, though. They react to others.
Like Dr. McCoy, I can mock Vulcans
Let me add a pair of methods to my Tribble
class:
[sourcecode language=”groovy”]
String react(Klingon klingon) {
klingon.annoy()
"wheep! wheep!"
}
String react(Vulcan vulcan) {
vulcan.soothe()
"purr, purr"
}
[/sourcecode]
The overloaded react
method is based on a pair of interfaces. Here’s the Vulcan
interface:
[sourcecode language=”groovy”]
interface Vulcan {
def soothe()
def decideIfLogical()
}
[/sourcecode]
Here’s the Klingon
interface:
[sourcecode language=”groovy”]
interface Klingon {
def annoy()
def fight()
def howlAtDeath()
}
[/sourcecode]
(Yeah, I know howling at death is a Next Generation thing, but go with it.)
Since both Vulcan
and Klingon
are interfaces, a mocking framework can generate an implementation with just Java’s basic dynamic proxy capabilities, which means I don’t need CGLIB in my classpath. To test the react
method that takes a Vulcan
, here’s the Spock mocking feature in action:
[sourcecode language=”groovy”]
def "reacts well to Vulcans"() {
Vulcan spock = Mock()
when:
String reaction = tribble.react(spock)
then:
reaction == "purr, purr"
1*spock.soothe()
}
[/sourcecode]
Spock provides the Mock
method to create a mock implementation of the interface. When I then invoke the react
method, I check that it returns the proper String
and (here’s the cool part), I verify that the soothe
method in the mock is invoked exactly once.
So far, so good. Klingons react rather badly to tribbles, however, so I thought it would funny if I had them throw an exception. Here’s my original test for the react
method that takes a Klingon (warning: this doesn’t do what it looks like it does!):
[sourcecode language=”groovy”]
def "reacts badly to Klingons"() {
Klingon koloth = Mock()
koloth.annoy() >> { throw new Exception() }
when:
String reaction = tribble.react(koloth)
then:
0*koloth.howlAtDeath()
1*koloth.annoy()
reaction == "wheep! wheep!"
notThrown(Exception)
}
[/sourcecode]
Using the right-shift operator, my intention was to set the expectation that invoking the annoy
method on a Klingon resulted in an exception. The plan was:
- In the setup block (above
when
), declare that theannoy
method throws an exception, - In the
then
block, verify that the method got called.
The problem is, what happens to the exception? Spock has two great methods for exception handling, called thrown
and notThrown
. I was able to verify that the method got called, but why did notThrown(Exception)
return true? I even got back the string I expected. What’s wrong?
The right way to mock a Klingon
(from a galaxy far, far away, right?)
Here’s the problem: according to the Spock wiki page on Interactions, interactions defined outside a then
block (here declaring that react
throws an exception) are called global, while those defined inside a then
block are called local, and local overrides global. Also, interactions without a cardinality are optional, while those with a cardinality are required.
In other words, I may have declared that react
throws an exception, but in the then
block I then changed it to say it actually doesn’t. In the then
block, I say that react
must be called once and doesn’t return anything. Therefore, no exception is thrown and the return value is as expected.
To achieve what I was actually after, here’s the right way to mock my Klingon:
[sourcecode langauge=”groovy”]
def "reacts badly to Klingons"() {
Klingon koloth = Mock()
1 * koloth.annoy() >> { throw new Exception() }
0 * koloth.howlAtDeath()
when:
String reaction = tribble.react(koloth)
then:
reaction == null
thrown(Exception)
}
[/sourcecode]
Now I set both the cardinality and the behavior outside the then
block. The then
block verifies both that the exception was thrown, and it checks the cardinality, too. Oh, and while I was at it, I verified that the howlAtDeath
method didn’t get called. I doubt the Klingons howled at death when they burned down all the tribbles that Scotty beamed into their engine room just before they went to warp.
Admittedly, I still find the syntax a bit confusing, but at least I get it now. Hopefully you’ll get it, too, and they’ll be nah tribble at all.
(The source code for this example and the others used in my NFJS the Magazine article are in my GitHub repository, https://github.com/kousen/Spock-NFJS-Article . Eventually they will make their way into my book, Making Java Groovy, available now through the Manning Early Access Program.)
Leave a Reply