Are you ready for Next-Gen Unit Testing for Java? It !!

If you are a Java Developer, this blog post is for you to ease your life a bit and add efficiency also.

Let me come to the point straight and ask you a few questions?

Are you thinking Junit or TestNG based unit testing is not encouraging you to do Test/Behavior Driven Development?

Are you vexed with including third-party libraries for mocking/stubbing and living with their limitations?

Are you confident that your unit testing covers all features of your application?

Are you interested to learn Dynamic programming, metaclass features to do unit testing easily?

Are you worried that you need to write a lot of boilerplate coding than focusing on testing?

Are you ever think of your scenarios speak themselves as tests and see which are failed or which are not?

Are you able to move to behavior-driven development with ease from the current state?

For any of the above questions, your answer is Yes, its time to you to introduce yourself to SPOCK !!

Unit tests in both JUnit and TestNG are written in Java as well. Traditionally, this has been seen as an advantage by Java developers because they use the same programming language in both production code and testing code. Java is a verbose language (at least by today’s standards) with a lot of boilerplate code, several constraints (for example, all code must be part of a class, even static methods), and a heavy syntax requiring everything to be explicitly defined. Newer editions of Java (after version 7) attempt to rectify this issue with mixed success, never reaching the newer “convention-over-configuration” paradigm of other programming languages.

In fact, production and testing code have completely different requirements. The biggest difference is that testing code runs by definition before the application is deployed in production. A good engineer uses the best tool for the job.

You can think of Spock as a special domain language created exclusively for testing purposes.

What is Spock?

Spock is a comprehensive testing framework for Java (and Groovy) code that can help you automate the boring, repetitive, and manual process of testing a software application. Spock is comprehensive because it’s a union of existing Java testing libraries, as shown below.

As the figure shows, Spock is a superset of the de facto testing framework for Java: JUnit. Spock also comes with built-in capabilities for features that normally require additional libraries.

At its core, Spock is a testing framework capable of handling the full lifecycle of a software application.

In a nutshell, Spock aims to be a more powerful alternative to the traditional JUnit stack, by leveraging Groovy features.

Spock tests are written in Groovy, but they can test either Groovy or Java code.

Groovy..!! ??

Don’t worry, Groovy is a kind of cakewalk for Java Developer and goes with Apple design thinking, familiar yet new.

Groovy is a JVM-based language that seamlessly integrates with Java. On top of interoperability, it offers additional language concepts such as being a dynamic, having optional types, and meta-programming.

By making use of Groovy, Spock introduces new and expressive ways of testing our Java applications, which simply aren’t possible in ordinary Java code. We’ll explore some of Spock’s high-level concepts during this blog, with some practical step by step examples.

If you are a Java developer but haven’t heard about Groovy, don’t worry — Groovy will feel very familiar to you! In fact, one of Groovy’s main design goals is to be the scripting language alongside Java. So just follow along and consult the Groovy documentation whenever you feel like it.

How do tests in Spock look?

As we are writing our tests in Groovy, we need to add them to the src/test/groovy directory, instead of src/test/java. Let’s create our first test in this directory, naming it Specification.groovy:

class FirstSpecification extends Specification {
def "one plus one should equal two"() {
expect:
1 + 1 == 2
}
}

Note that we are extending the Specification interface. Each Spock class must extend this in order to make the framework available to it. It’s doing so that allows us to implement our first feature:

Before explaining the code, it’s also worth noting that in Spock, what we refer to as a feature is somewhat synonymous with what we see as a test in JUnit. So whenever we refer to a feature we are actually referring to a test.

Now, let’s analyze our feature. In doing so, we should immediately be able to see some differences between it and Java.

  • The first difference is that the feature method name is written as an ordinary string. In JUnit, we would have had a method name that uses camelcase or underscores to separate the words, which would not have been as expressive or human-readable:
  • The next is that our test code lives in an expect block. We will cover blocks in more detail shortly, but essentially they are a logical way of splitting up the different steps of our tests.
  • Finally, we realize that there are no assertions. That’s because the assertion is implicit, passing when our statement equals true and failing when it equals false.

Sometimes when writing JUnit a test, we might notice there isn’t an expressive way of breaking it up into parts. For example, if we were following behavior-driven development, we might end up denoting the given when then parts using comments:

@Test
public void givenTwoAndTwo_whenAdding_thenResultIsFour() {
// Given
int first = 2;
int second = 4;
// When
int result = 2 + 2;
// Then
assertTrue(result == 4)
}

Spock addresses this problem with blocks.

Blocks are a Spock native way of breaking up the phases of our test using labels. They give us labels for given when then and more:

  • Setup (Aliased by Given) — Here we perform any setup needed before a test is run. This is an implicit block, with code not in any block at all becoming part of it
  • When — This is where we provide a stimulus to what is under test. In other words, where we invoke our method under test
  • Then — This is where the assertions belong. In Spock, these are evaluated as plain boolean assertions, which will be covered later
  • Expect — This is a way of performing our stimulus and assertion within the same block. Depending on what we find more expressive, we may or may not choose to use this block
  • Cleanup — Here we tear down any test dependency resources which would otherwise be left behind. For example, we might want to remove any files from the file system or remove test data written to a database

Let’s try implementing our test again, this time making full use of blocks:

def "two plus two should equal four"() {
given:
int left = 2
int right = 2
when:
int result = left + right
then:
result == 4
}

Why Spock?

JUnit/TestNG and Mocking f/w is covering me for now, why something new?

As the title of this blog says, this is all about NextGen Testing where you have to do TDD or BDD, need meta-programming, powerful mocking/stubbing, expressing testing ( called as specifications), not any one of these, but all.

As the Spock website claims:

What makes it stand out from the crowd is its beautiful and highly expressive specification language. Thanks to its JUnit runner, Spock is compatible with most IDEs, build tools, and continuous integration servers. Spock is inspired from JUnit, jMock, RSpec, Groovy, Scala, Vulcans, and other fascinating life forms.

Spock offers below distinctive features as one package:

Enterprise Testing

Rather than reinventing the wheel, Spock bases its tests on the existing JUnit runner. The runner is responsible for executing JUnit tests and presenting their results to the console or other tools (for example, the IDE). Spock reuses the JUnit runner to get for free all the mature support of external tools already created by Junit. As an enterprise strategy, if TDD/BDD is part of the development cycle, Spock is already equipped and ready to serve you

Data-Driven Testing

Essentially, data-driven testing is when we test the same behavior multiple times with different parameters and assertions. A classic example of this would be testing a mathematical operation such as squaring a number. Depending on the various permutations of operands, the result will be different. In Java, the term we may be more familiar with is parameterized testing which is possible with JUnit with a lot of boilerplate code again. One easy win for Spock when compared to JUnit is how it cleanly it implements parameterized tests. Again, in Spock, this is known as Data-Driven Testing. Let’s see the difference straight away for both Spock and JUnit :

JUnit

@Test
public void acceptJpg() {
ImageNameValidator validator = new ImageNameValidator();
String pictureFile = "scenery.jpg";
assertTrue(validator.isValidImageExtension(pictureFile));
}
@Test
public void acceptJpeg() {
ImageNameValidator validator = new ImageNameValidator();
String pictureFile = "house.jpeg";
assertTrue(validator.isValidImageExtension(pictureFile));
}
@Test
public void doNotAcceptTiff() {
ImageNameValidator validator = new ImageNameValidator();
String pictureFile = "sky.tiff";
}

Spock:

def  "Valid images are PNG and JPEG files"() {
given: "an image extension checker"
ImageNameValidator validator =
new ImageNameValidator()
expect: "that only valid filenames are accepted"
validator.isValidImageExtension(pictureFile) ==
validPicture
where: "sample image names are"
pictureFile || validPicture
"scenery.jpg" || true
"house.jpeg" || true
"car.png" || true
"sky.tiff" || false
"dance_bunny.gif" || false
}

As we can see, we just have a straightforward and expressive Data table containing all our parameters.

Also, it belongs where it should do, alongside the test, and there is no boilerplate. The test is expressive, with a human-readable name, and pure expect and where block to break up the logical sections.

Mocking/Stubbing

In the JUnit world, an external library is needed for mocking. Numerous libraries exist, with both strengths and weaknesses — for example, Mockito, jMock, EasyMock and PowerMock Spock comes with its own built-in mocking framework. Combined with the power of Groovy meta-programming, Spock is a comprehensive package that provides all the puzzle pieces needed for testing.

In JUnit (through a 3rd party library) you need to make sure to initialize Mocks or annotate your class with @RunWith(MockitoJUnitRunner.class). In Spock though, you do not need to do this, because in Spock you have direct access to non-existing constructors, private fields, and more. As result, you can work even with Object references instead of Mocks, which is explained as below.

Java Class under test

public class Formatter() {     
private String message;
private int count;
}

Spock test:

class FormatterShould extends Specification {
def "get and set fields"() {
given: "formatter"
def formatter = new Formatter()
when: "setting a message"
formatter.message = 'message'

then: "setted message is correct"
formatter.message == 'message'
} }

This is a simple example where Spock accessed private class fields, which shows how powerful Spock is. Another complete mocking/stubbing example as below.

A detailed post on how mocking/stubbing is different and straight forward using Spock is explained here for reference,

Another killer features of Spock is the detail it gives when a test fails. JUnit mentions the expected and actual value, whereas Spock records the surrounding running environment, mentioning the intermediate results and allowing the developer to pinpoint the problem with greater ease than JUnit.

On the whole Spock provides more powerful features and expressive ways of testing without focusing on boiler plate code, meta programming, powerful mocking, data-driven testing, and supports TDD/BDD. For the same tests with Junit and Spock, you will definitely see the difference in number of lines of code need to write, which will be lower in Spock.

How should I start?

Spock takes a holistic approach, providing a superset of the capabilities of JUnit, while at the same time reusing its mature integration with tools and development environments. Spock can do everything that JUnit does and more, keeping backward compatibility as far as test runners are concerned. Because Spock is compatible with JUnit runners, it can be introduced gradually in an existing Java code base. Assuming you start with a 100% Java project, as shown below, Spock can run alongside JUnit tests in the same code base.

Spock is already distributed via Maven central, so using it in a Java forward is a painless process. We just need to modify the pom.xml and add the following dependencies and plugins.

Dependencies

<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.0-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.7</version>
<scope>test</scope>
</dependency>

Plugins:

<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

To summarize,

  • Spock is an alternative test framework written in the Groovy programming language.
  • A test framework automates the boring and repetitive process of manual testing, which is essential for any large application codebase.
  • Although Spock is written in Groovy, it can test both Java and Groovy code.
  • Spock has built-in support for mocking and stubbing without an external library.
  • Spock follows the given-when-then code flow commonly associated with the BDD paradigm.
  • Both Groovy and Java build and run on the JVM. A large enterprise build can run both JUnit and Spock tests at the same time.
  • Spock uses the JUnit runner infrastructure and therefore is compatible with all existing Java infrastructure. For example, code coverage with Spock is possible in the same way as JUnit with a better failure explanation.
  • Spock tests have the ability to include full English sentences in their code structures, allowing for easy documentation.

I tried to introduce this comprehensive, more powerful framework as JUnit alternative which can be your next choice to improve efficiency, productivity. With the power of Groovy, Spock can solve your testing needs more easily with a focus on tests. Hope this helps.

Happy Unit testing !!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store