Spock vs. JUnit: Which One Should You Choose?
January 25, 2021

Spock vs. JUnit: Which One Should You Choose?

API Testing

Spock vs. JUnit — which is the best framework for you? I break down the key differences in this blog.

 

Back to top

Spock vs. JUnit: Which Is Best?

The main difference between Spock and JUnit is in breadth of capabilities. Both frameworks can be used for unit testing. However, Spock offers much more — including mocking and integration testing. JUnit requires a third party library for mocking.

 

Spock and JUnit are both great testing frameworks for Java. And both can be used for API testing. Personally, as an information technologies engineer, I prefer using Spock, and not only because it supports Groovy. In my opinion, Spock is easier and nicer to use. Inspired by JUnit, jMock, RSpec, Groovy, Scala and Vulcans, it enjoys a combined set of advantages. JUnit, on the other hand, is a very mature framework, and a very large audience enjoys its abilities.

 

Back to top

Key Differences in Spock vs. JUnit

Let's compare Spock and JUnit according to four parameters:

 

1. Parameterization

Parameterization is the technique of changing test data for the same test method, thus making the test run the same code but for changing data. We will often need to use parameterization in our test cases. Let’s look at a simple example that shows why.

Imagine we have a method that gets the filename as input and validates its extension. The requirement is that only jpeg, jpg and bmp extensions pass, while tiff and png extensions are not allowed at all. This method will return ‘true’ or ‘false’ based on the file extension. As we can see, the code for checking each file extension should be the same, except for the extension itself. Parameterization will make the code the most efficient and easy to work with.

Let’s see how parameterization works in Spock and in JUnit:

Spock (19 lines - empty lines not counted):

import spock.lang.Specification
import spock.lang.Unroll

@Title("Testing file extension validation method")
class ImageValidatorShould extends Specification {
  
   @Unroll
   def "validate extension of #fileToValidate"() {
       when: "validator checks filename"
       def isValid = validate fileToValidate

       then: "return appropriate result"
       isValid == expectedResult

       where: "input files are"
       fileToValidate || expectedResult
       'some.jpeg'    || true
       'some.jpg'     || true
       'some.tiff'    || false
       'some.bmp'     || true
       'some.png'     || false
   }
}

 

JUnit (30 lines - empty lines not counted):

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import java.util.Collection;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;

@RunWith(Parameterized.class)
public class ImageValidator {

   @Parameters
   public static Collection<Object[]> data() {
       return asList(new Object[][]{
               {"some.jpeg", true},
               {"some.jpg", true},
               {"some.tiff", false},
               {"some.bmp", true},
               {"some.png", false}
       });
   }

   private String file;
   private boolean isValid;

   public ImageValidator(String input, boolean expected) {
       file = input;
       isValid = expected;
   }

   @Test
   public void validateFileExtension() {
       assertEquals(isValid, validate(file));
   }
}

 

As we can see from the code snippets, the JUnit code is more than 50% longer. In addition, it is readable for Java developers, but for all others Spock is much more readable and clean.

Personally, as a Java engineer, when I saw Spock first time I had a feeling that it was not clean and understandable. But I gave it some time and experimented with it, and now all my tests are only in Spock.

Now let’s take a look at the execution output for these code snippets:

Spock:A screenshot of Spock execution code snippets.

 

JUnit:A screenshot of JUnit execution code snippets.

 

Here, as we can see from execution times, JUnit is winning as it is much faster. But, Spock is nicer and the output provides more information about the extensions.

2. Mocking

Mocking is the technique of creating objects in the code that aren’t real, but they simulate the behaviour of real objects instead. Mocking is used to isolate the behaviour of a certain object, by using mocks for all the other objects except the one being tested. Please note that mocks aren’t Stubs. Read more about Mocking and the difference between Mocking and Stubbing from Martin Fowler’s web page.

For mocking (as well as stubbing) in Java (and more or less in all languages), you need to include a 3rd party library like EasyMock or Mockito. In Spock though, you do not need anything from a 3rd party. Spock itself is enough with its Mock().

Mocking (as well as Stubbing) in Spock is as easy as the following code:

def subscriber = Mock(Subscriber)
def receiver = Stub(Receiver)

 

In JUnit though, you need to do a bit more for Mocking (and Stubbing):

 

  • Choose a 3rd party library
  • Annotate the variable or field with @Mock
  • Initialise the mocks

 

@Mock
private Subscriber subscriber;

@Before
public void setup() {
	subscriber = new Subscriber()
}

 

 

Another important thing to mention is mock injection. Mock injection is the act of putting Mocks into Mocked classes.

In JUnit (through a 3rd party library) you need to make sure to initialise 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. Let me show this in the following code snippets:

Java class:

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

 

Spock:

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"
       assert formatter.message == 'message'
   }
}

 

JUnit (only possible when you have public accessors or a public constructor that has access to private fields):

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

      public Formatter(String message, int count) {
          this.message = message;
          this.count = count;
      }
}

 

This is a simple example where Spock accessed private class fields, which shows how powerful Spock is.

 

3. Documenting Tests and Code

In every piece of developed code, it is good practice to have self explaining methods, variable names and class names, objects, etc., especially when we need to work on legacy code. The same applies to test methods/classes, even more than for regular code, because regular code passes lots of quality gates and tests. So let’s see the differences between Spock and JUnit in this field.

In Spock, the code snippet documents our code by default. We have the @Title explanation for the whole test class, then in every test method we have given/when/then/{where} blocks and they all have explanations. Also, we have the test method name written in the simple and understandable English.

On the other hand, JUnit is losing on all levels, because there is no documentation “forced” by default. So if you want it, you have to develop brilliant self explanatory code yourself (let’s be fair here, in the legacy code this is almost impossible) and at least some comments should be added.

 

4. Verification

In JUnit, to assure a method was executed based on some condition(s), you have to have 3rd party dependencies, e.g. Mockito.

verify(someMockedClass).someMethod(isA(Some.class));

 

Exactly the same login in Spock will look like this:

1 * someMockedClass.someMethod

 

Note that for doing this in Spock you do not need 3rd party libraries.

 

The then() of Mockito used in JUnit (and other frameworks) looks like this:

when(someClass.someMethod(TEST)).thenReturn(result);

 

Yet in Spock you will have much less code and readability

someClass.someMethod(TEST) >> result

 

In other words, Spock uses 0* and >>, while JUnit uses verify() and then() .

Back to top

So, Should You Use Spock or JUnit?

As we can see, Spock has more readability and a clearer documented code, it does not need 3rd parties, and it is more powerful than JUnit. In the end, using Spock or JUnit or TestNG or anything else is absolutely up to you. They each have their pros and cons for sure.

One thing I can say though, it’s that in the past I used JUnit and TestNG. But when I heard about and experimented with Spock, I switched to it completely. If you switch to Spock from any other tool you might struggle in the beginning, but pretty quickly you will enjoy a clean and maintainable tool with documented test code. 

This blog was originally published on January 25, 2018 and has since been updated for accuracy and relevance.

START TESTING NOW

 

Related Resources:

Back to top