Testing Spring Boot Applications with Spock

I am starting to get familiar with Spring Boot thanks to the Guides on Spring.io and the samples that come with the project itself.

As a Grails developer, I love the Spock testing framework. Spock is a testing and specification framework that fully leverages groovy to help you write succinct and highly expressive tests. You can read more about Spock in the Framework documentation.

In this post, I want to show how you can use Spock to add easily readable tests for your Spring Boot applications.

Let’s start with the getting started with Spring Boot tutorial

Follow the steps of the Java portion of the tutorial until you have a fully running application. If you wish to skip this step, the github repo comes with a completed example under the complete directory.

Add Spock and groovy to your Gradle Build

As we’re going to write our tests in Groovy, we are going to add the groovy plugin for Gradle. We are also going to replace the jUnit dependency with Spock.

Change the line that says

apply plugin 'java'

to

apply plugin 'groovy'

Next, change the jUnit dependency to the spock and groovy dependencies.

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M2") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile "org.springframework.boot:spring-boot-starter-jetty:0.5.0.M2"
    compile "org.springframework.boot:spring-boot-starter-actuator:0.5.0.M2"
    testCompile "org.codehaus.groovy:groovy-all:2.1.7"
    testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
}

Your final build.gradle file should look like this.

Import Your Project into IntelliJ Idea

The Gradle idea ( and eclipse ) plugins allow you to use an IDE to work with your files and run tests.

In a terminal window, run

./gradlew idea

This will create an intelliJ idea project based on your build.gradle file. Open this project in IntelliJ Idea. You should see something like this.

Screen Shot 2013-09-19 at 12.27.35 AM

Writing and Running Your first Spock Specification

Let’s write a simple Spock specification to make sure everything is set up correctly.

Create a new groovy file under src/test/groovy/hello/HelloControllerSpec.groovy

Add the following into it:

package hello

import spock.lang.Specification

class HelloControllerSpec extends Specification{

    void "testing spock works"(){
        expect:
        true
    }

}

In this file, we extend Spock Specification so that Spock knows this is a test.

We have a feature in Spock we’re testing called “testing spock works”. This is a descriptive method that describes the thing we are testing. I hope you can see how nice it is to express the method in natural language instead of programmese.

Under the spec, we have an expect: block. Spock allows us to use labels normally associated with Behaviour Driven Development story templates. We will see some more of these later when we write our real test.

To run our test, we can use our terminal and type

./gradlew test

This will run our tests and produce a test report we can read.

But since we are using an IDE, we can also run this spec from Idea and get feedback immediately. Right click on the file name and select ‘Run HelloControllerSpec’.

Screen Shot 2013-09-19 at 12.33.27 AM

You should see a small window pop up with the spec that you just ran:

Screen Shot 2013-09-19 at 12.33.59 AM

Testing the HelloController

In the Spring.io guide, we wrote a controller that looks like this:

@Controller
public class HelloController {
    @RequestMapping("/")
    public @ResponseBody String index() {
        return "Greetings from Spring Boot!";
    }
}

There is also an Application.java file we wrote that sets up a server and runs the controller.

In this section, we’re going to start up a test server in Spock and make sure it works as expected.

In the Spring Boot samples, there is a jUnit test that is very similar to what we want to do, you can see it here.

The corresponding test, written in Spock, looks like this:

package hello

import org.springframework.boot.SpringApplication
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.client.RestTemplate
import spock.lang.Shared
import spock.lang.Specification

import java.util.concurrent.Callable
import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit

class HelloControllerSpec extends Specification {

    @Shared
    ConfigurableApplicationContext context

    void setupSpec() {
        Future future = Executors
                .newSingleThreadExecutor().submit(
                new Callable() {
                    @Override
                    public ConfigurableApplicationContext call() throws Exception {
                        return (ConfigurableApplicationContext) SpringApplication
                                .run(Application.class)
                    }
                })
        context = future.get(60, TimeUnit.SECONDS)
    }

    void cleanupSpec() {
        if (context != null) {
            context.close()
        }
    }

    void "should return Greetings from Spring Boot!"() {
        when:
        ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080", String.class)

        then:
        entity.statusCode == HttpStatus.OK
        entity.body == 'No Greetings from Spring Boot!'
    }

}

Starting and shutting down the Application Server

In the same vein as the jUnit test, we start up an application server when we enter the test and shut it off when the test is finished. Instead of the @BeforeClass and @AfterClass annotations in jUnit, we simply call setupSpec() and cleanupSpec() in Spock.

Testing the Controller Logic

Compare the jUnit test:

public void testHome() throws Exception {
	ResponseEntity entity = getRestTemplate().getForEntity(
			"http://localhost:8080", String.class);
	assertEquals(HttpStatus.OK, entity.getStatusCode());
	assertEquals("Hello World", entity.getBody());
}

to the Spock equivalent:

 void "should return Greetings from Spring Boot!"() {
        when:
        ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080", String.class)

        then:
        entity.statusCode == HttpStatus.OK
        entity.body == 'No Greetings from Spring Boot!'
    }
  • The first thing you might notice is that the method name is Spock is slightly more descriptive.
  • We also separate the inputs and outputs of the code being tested with the when -> then labels. If I wanted to, I can also add a text label after the tag so it looks like
    when:'I go to the homepage'
    ...
    then:'I get a greeting'
    

    These labels can then be extracted with a tool like the Spock HTML Report plugin to define my stories.

  • Instead of asserts, Spock allows me to simply set a == in my then blocks. This allows my test to be slightly more readable.

Expressive Test Failures

I have purposely written this test so that it generates a test failure. Spock uses a feature called power asserts which gives you a very expressive output when a test fails. It looks like this:

Condition not satisfied:

entity.body == 'No Greetings from Spring Boot!'
|      |    |
|      |    false
|      |    3 differences (90% similarity)
|      |    (---)Greetings from Spring Boot!
|      |    (No )Greetings from Spring Boot!
|      Greetings from Spring Boot!
<200 OK,Greetings from Spring Boot!,{Content-Length=[27], Content-Type=[text/plain;charset=ISO-8859-1], Server=[Jetty(8.1.9.v20130131)]}>
 <Click to see difference>

	at hello.HelloControllerSpec.should return Greetings from Spring Boot!(HelloControllerSpec.groovy:47)

In this output, you can see where the test expression fails and see the output from each level of the test. This is very useful for error diagnosis. Moreover, IntelliJ has really good support for this, so when I click on see difference, I am presented with a comparison dialog:

Screen Shot 2013-09-19 at 1.40.05 AM

AutoCleanup

I can make my test simpler by getting rid of my cleanupSpec and changing my context definition to the following:

    @Shared
    @AutoCleanup
    ConfigurableApplicationContext context

The autoCleanup feature simply calls close on the context once my spec has finished. It is quite handy.

Adding more features

Let’s say I want to add another endpoint to my application so that it reverses the input that I send to the controller. True to proper TDD, I will first write a failing Spock test:

Adding another test

   void "should reverse request!"() {
        when:
        ResponseEntity<String> entity = new RestTemplate().getForEntity(url, String.class)

        then:
        entity.statusCode == HttpStatus.OK
        entity.body == reversedString

        where:
        url                                 || reversedString
        'http://localhost:8080/reverse/uno' || 'onu'
        'http://localhost:8080/reverse/ufc' || 'cfu'
    }

Here, I use a handy feature in Spock called Data Tables. This allows me to define multiple iterations of a test and define the data for the test in each row of the where label. Data tables are really powerful and I recommend you read up on them here.

You can see the finished Spec here.

Implementing the feature

Now that we have a failing test, we can simply add the request mapping to our controller:

    @RequestMapping("/reverse/{stringToReverse}")
    public
    @ResponseBody
    String reverse(@PathVariable String stringToReverse) {
        return new StringBuilder(stringToReverse).reverse().toString();
    }

We run the tests and see that it all works correctly.

Summary

Hopefully, this post shows you how easy and expressive it is to use Spock with your Spring Boot applications. I hope that you have found it as useful as I have.

You can find the finished application on github with a full commit history.

About these ads

6 thoughts on “Testing Spring Boot Applications with Spock

  1. Herick Oliveira

    Thank you for this. I was merely looking for a good way to test Spring Boot applications, but in the process I got to know Spock, which I’m now really insterested in.

    Reply
  2. Peter N. Steinmetz

    Is the use of future and delayed execution necessary here in setupSpec. I eliminated it from an application not using the web interface (just the spring-boot-starter) and it worked fine.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s