IntelliJ IDEA Tutorials Videos

Tutorial: Spock Part 4 – Mocking and Stubbing

In Part 4 of our Spock tutorial, we look at mocking and stubbing. The Spock framework has mocking and stubbing built in. Creating, using and verifying mocks and stubs is nicely aligned with the way the tests are written, and can lead to very readable tests.

Tutorial: Spock

These blog posts cover the same material as the video. This provides an easy way for people to skim the content quickly if they prefer reading to watching, and to give the reader/watcher code samples and links to additional information.

Mocks

Sometimes we need to mock out classes or APIs to assert the expected behaviour. Mocking is built in to Spock, we don’t need a separate library or framework for Mock support. It’s also possible to mock concrete classes. If you’re used to other Mocking frameworks you might expect to only be able to mock Java interfaces, but Spock lets us easily create a mock from a concrete class.

The given block of a Spock test is the perfect place to set up mocks for our test. It’s clear then that this is all code that’s required to run the test, but is not the code that’s being tested itself.

def "should be able to mock a concrete class"() {
    given:
    Renderer renderer = Mock()
    def polygon = new Polygon(4, renderer)

    when:
    polygon.draw()

    then:
    4 * renderer.drawLine()
}

This test mocks a Renderer class, which is a concrete Java class. We can do this either by declaring a variable with type Renderer, and calling Mock without any arguments:

Renderer renderer = Mock()

…or if we prefer to use Groovy’s def to define our variables, we’ll need to pass the type in as an argument to the Mock method:

def renderer = Mock(Renderer)

Bear in mind that if you declare it using “def”, this variable is using Groovy’s dynamic typing, and so isn’t strongly recognised as a Renderer type by the IDE or by the code. This is fine if you’re not doing much with the mock, but you might sometimes want to specify the type more clearly, this will certainly be more natural for Java developers.

The given block also sets up a Polygon with the given renderer, calling the constructor with the numberOfSides and the mocked renderer.

The when section defines the call that’s actually the thing we’re testing, in this test we want to see what happens when we call the draw method on this polygon. Make sure there’s a draw method on the polygon, at this stage it can be empty because we’re doing a bit of TDD:

public void draw() {
}

The then block defines the expectations. Spock has a nice, clear syntax for defining the behaviour we expect to see on the mock. In this test, we might expect to see four calls on the renderer’s drawLine method, given that the polygon has four sides. The then block states we expect to see renderer.drawLine called 4 times.

Run this test now, it should fail. This is because the methods don’t do anything yet. We expected to see this drawLine method called four times, but it wasn’t called at all.

Go into the implementation of the Polygon.draw method and change it to call the renderer’s drawLine method in here as many times as there are sides (note that this is an extremely over-simplified example to demonstrate the testing):

public void draw() {
    for (int i = 0; i < numberOfSides; i++) {
        renderer.drawLine();
    }
}

Re-run the test, it should pass. The code is calling drawLine on the renderer mock four times.

Mocks are a powerful and useful tool to make sure that the code that we’re testing is calling the APIs that we expect, in the way we expect.

View steps in video

Stubs

Mocks are useful for checking calls out of our code, Stubs are useful for providing data or values into the code we’re testing.

Let’s see an example of a stub in a new test method.

def "should be able to create a stub"() {
    given:
    Palette palette = Stub()
    palette.getPrimaryColour() >> Colour.Red
    def renderer = new Renderer(palette)

    expect:
    renderer.getForegroundColour() == Colour.Red
}

The given block sets up the preconditions for the test. This time, we’re going to use the Stub() method to create a Stub of the concrete Palette class. Like with Mock(), you can define it this way, or use def and pass the type into the Stub() method.

Next the test sets up the palette stub with the values it will produce when called by our code. We use right-shift (>>) to state that when the method getPrimaryColour is called, the Enum value Red will be returned.

The last step of setup is to create the Renderer with this stub palette. If you’re following along with this code in the IDE, make sure your Renderer looks something like:

public class Renderer {
    private Palette palette;

    public Renderer(Palette palette) {
        this.palette = palette;
    }

    public void drawLine() {
    }
}

The test uses an expect label because the test and the assertion are combined – we expect that when we call getForegroundColour, this will return Colour.Red. This test states that we expect getForegroundColour to return the same colour as the palette’s primary colour.

Once again, we can use test-driven development here – we can use the test to drive out what we expect the methods to look like even if they don’t exist yet. Use ⌥⏎ (macOS), or Alt+Enter (Windows/Linux), on any red method names to get IntelliJ IDEA to create the most basic methods that makes the code compile, then run the test.

It should fail if we haven’t implemented the details for getForegroundColour. It’s good to see the test fail first, it often indicates the test is checking the right thing, even if that right thing hasn’t been implemented yet.

Change the getForegroundColour method to return the palette’s primary colour.

public Colour getForegroundColour() {
    return palette.getPrimaryColour();
}

Re-run the test, it should pass. The test injects a Stub palette into the renderer, we tell the stub palette what to return when the getPrimaryColour method is called, so we can check that the renderer does what it’s supposed to do when we call getForegroundColour.

If we had set this up as a Mock instead of a Stub, this would have worked as well. Mock objects support the mocking behaviour we saw in the previous test and the stubbing behaviour we saw here, whereas Stub objects only support stubbing, and not mocking. My preference is to keep stub and mock behaviour separate where possible, so it’s usually best to use Stubs just for stubbing and Mocks only for mocking.

View steps in video

Conclusion

In this blog, we looked at mocking and stubbing. Now you know how to:

  • Create a mock and write a test that shows a particular method was called when the test was run
  • Create a stub to provide an expected value, so a test can verify that expected value is used

Spock has much more to offer than this, stay tuned for further blog posts, watch the full video, or take a look at the excellent reference documentation.

image description

Discover more