JUnit vs Spock + Spock Cheatsheet

May
14th,
2016

If you are not familiar with spock it is testing framework for Groovy and Java.
It’s been stable for quite some time and I highly recommend you to check it out
if you are annoyed by Junit and Java’s style of writing tests.

What’s wrong with JUnit + <some mocking framework> ?

The standard way of testing Java application is to use Junit
and some mocking framework (Mockito,EasyMock, PowerMock etc.).

Java combined with those frameworks makes it rather hard to
write and read tests in medium and large sizes projects:

You cannot set title for a test (Junit5 introduces this feature but it is still in alpha). Instead you have
to name your method in a ridiculous way like ‘shouldAddToCartIfItemIsAvailaibleAndTheLimitIsNotExceededAnd…..’.

The intent of the test is blurred by all those Java and mocking framework verbosity like
Collections.singletonList()’s,replay’s,verify’s or any(MyAwesomeAbstractFactoryBaseClass.class)’s and many more.

There is no good way to separate sections responsible for different phases (given,when,then).
Some people use comments to mark those sections but I think it’s even worse than not having them at all.

Java is certainly not easy language for building “expected” objects - everything is so verbose.
Once again - it hides the intent of a test.

Parametrizied tests are kinda weird too. They must be stored in fields,
and you can only have one set of them per test class.

Since parametrized test are not simple you usually
write gazillion of separate methods - each covering different case, or even worse
skip some cases hoping noone will notice :).

If tests are hard to write we usually think of them
as something painful and start to neglect them.
Avoiding or delaying writing tests leads to the situation where application cannot be trusted anymore.
We then become afraid of making any changes because other part of the app might
break in some bizarre way.

It shouldn’t be this way. Test should be easy and fun to write. After all
they are like a cherry on top, proving that the features are implemented correctly.

In my opinion the most important responsibility of the test is to be as most readable as possible.
Business changes to the project are introduced all the time. If we change something in the
application we have to change test too (unless you’re applying open-closed principle, which I’ve never heard
of anyone successfully adapting :D). If tests are hard to read there is a big problem.

On the other hand - these are just my opinion, who am I to judge? Do you feel similar about this topic
or is it just me? If you disagree, or have some objections leave a comment!

Spock

Spock is both testing and mocking framework. What’s more it extends
Junit runner so it can be runned by the tools you
used for your tests before.

The best thing about Spock is that it’s basically a DSL (domain specifing language) for writing tests.
It’s based on Groovy and is designed particularly testing. It introduces some syntax
features just for that purpose. You may therefore expect some neat stuff in it (which is indeed correct).

Groovy is kinda like a scripting version of Java - simple, less verbose but retains all the power of JVM.

Cheatsheet

This cheatsheet contains the most useful spock features regarding testing Java applications.
Most of this is copy-paste from official spock documentation. I compiled it
while I was learning the framework to have all information in one place.
I figure out since it’s already compiled why not share it on a blog too.

Basics

Specification template

Fixture Methods

defsetup(){}// run before every feature methoddefcleanup(){}// run after every feature methoddefsetupSpec(){}// run before the first feature methoddefcleanupSpec(){}// run after the last feature method

Interaction Based Testing

Mocking

Create mock

Using mock

def"should send messages to all subscribers"(){when:publisher.send("hello")then:1*subscriber.receive("hello")//subsriber should call receive with "hello" once.1*subscriber2.receive("hello")}

Cardinality

1*subscriber.receive("hello")// exactly one call0*subscriber.receive("hello")// zero calls(1..3)*subscriber.receive("hello")// between one and three calls (inclusive)(1.._)*subscriber.receive("hello")// at least one call(_..3)*subscriber.receive("hello")// at most three calls_*subscriber.receive("hello")// any number of calls, including zero// (rarely needed; see 'Strict Mocking')

Constraints

Target

1*subscriber.receive("hello")// a call to 'subscriber'1*_.receive("hello")// a call to any mock object

Method

1*subscriber.receive("hello")// a method named 'receive'1*subscriber./r.*e/("hello")// a method whose name matches the given regular expression// (here: method name starts with 'r' and ends in 'e')

Argument

1*subscriber.receive("hello")// an argument that is equal to the String "hello"1*subscriber.receive(!"hello")// an argument that is unequal to the String "hello"1*subscriber.receive()// the empty argument list (would never match in our example)1*subscriber.receive(_)// any single argument (including null)1*subscriber.receive(*_)// any argument list (including the empty argument list)1*subscriber.receive(!null)// any non-null argument1*subscriber.receive(_asString)// any non-null argument that is-a String1*subscriber.receive({it.size()>3})// an argument that satisfies the given predicate// (here: message length is greater than 3)