Along with pair programming, using a cutting-edge IDE called "IntelliJ" and using a continuous integration server, we adhered strictly to test-driven development, using JUnit. This was a fairly kooky practice at the time, and in an era predating things like annotations, unit tests had to extend from a base JUnit class.
As the years continued to roll by, I stood by the practice of TDD and rejoiced at the introduction of new libraries and techniques. Mocking out dependencies was a revelation, and I thought EasyMock was the bee's knees. Then Mockito came along and blew the lid off of everything.
For a good few years, I felt I'd plateaued -- writing what I thought were fantastic tests, laden with @Mock annotations and builder pattern-style callouts for the behavior I wanted to provide. Not to mention the anonymous inner classes for flexible "matchers." I stood dutifully by my practice of hammering out long and elaborate tests, many of which were insanely difficult to read at the end of it. "At least I have regression protection," I would tell myself, and sneer at my fellows that eschewed testing.
It wasn't until a couple of years ago that a new technology came around and turned my understanding of testing completely upside down. This coincided with my first full-on brush with the Groovy language.
This revelation was spock. Of all of the technologies, libraries, techniques and platforms I've come across in the last several years, I'd call spock the best and most interesting one. Spock is perfectly representative of what makes Groovy a great language. It's also learned from the things that made testing in a world of dependency injection so painful.
Rather than using something like JUnit and picking some sort of a mocking library, you get all of this with spock. It has its own powerful mocking concept, taking full advantage of Groovy's proxying capabilities. It also makes things like mocking out static methods a snap.
The features and functionalities of spock aren't its greatest virtues, however. What makes spock great is how expressive it is. In case you're not familiar, this is what a spock test looks like:
def "Calls the payment service and returns the result"() {
setup:
PaymentController controller = new PaymentController()
controller.paymentService = Mock(PaymentService)
when:
PaymentResult result = controller.pay("MyAccount", 55.50)
then:
1 * controller.paymentService.acceptPayment("MyAccount", 55.50) >> new PaymentResult(accepted: true)
result.accepted
}
What you're seeing here is something that reads like prose. And the beauty of it is that verification and behavior are captured in a single line. Using the rather old school concept of labels, Spock is able to skip from block to block in the method. No assertion statements are required in the verification block.
Do you remember how this looked with JUnit?
You would have to spell out the behavior before your method call with a chained statement, looking something like:
when(controller.pay(eq("MyAccount"), eq(55.50))).thenReturn(new PaymentResult())
Further down the line, you would have to verify the behavior
verify(controller).pay( ... )
And you'd have to call out the matching parameters once again. If you're disciplined enough, you can keep your JUnit pretty tight. But frankly, when I've had to work with legacy code in my post-spock career, I've found myself trying to cram everything into the BDD-style given/when/then flow.
What surprises me about spock is that it hasn't taken off at an even greater speed. I overheard some coworkers from a different project talking about spock today, and both of them were clearly unfamiliar with it. I'll admit that I was reticent about embracing spock at first, but even then I recognized how readable and succinct the tests were.
Even if you're saddled with writing Java as your production code, I highly recommend tapping into spock as your testing platform. There are a few gotchas (Mock/GroovyMock/Spy/GroovySpy) when you're strictly using Java, but it's well worth it.
Remember, a good test will generally result in good, tight code.