Loading...

January 25, 2011

Spocklight: Add Spock Support to Java Project in STS/Eclipse

Suppose we get assigned to an existing Java project and we want to use Spock for writing our tests (of course!). In this post we learn the steps we need to take to achieve this. We assume the Java project is built with Maven and imported into SpringSource Tool Suite (or Eclipse). For an easier way to add Spock to STS/Eclipse using Gradle we can read this blog post written by Ken Kousen.

First we start with our Java project. The project for this sample is very simple. We only have one interface and an implementation class for finding a username in a list of users. The sources for this post can be found at Github. The following pom.xml is used:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.mrhaki.app.services</groupId>
    <artifactId>user-service</artifactId>
    <packaging>jar</packaging>
    
    <name>User Service</name>
    <description>Service to work with users</description>
    
    <version>1.2</version>

</project>

This project is imported as Maven project into SpringSource Tool Suite. Now it is time to add Spock support to our project. First we change the pom.xml and add the required plugins and dependencies:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mrhaki.app.services</groupId>
    <artifactId>user-service</artifactId>
    <packaging>jar</packaging>

    <name>User Service</name>
    <description>Service to work with users</description>

    <version>1.2</version>

    <properties>
        <spock.version>0.5-groovy-1.7</spock.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.gmaven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <configuration>
                            <providerSelection>1.7</providerSelection>
                        </configuration>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.gmaven.runtime</groupId>
                        <artifactId>gmaven-runtime-1.7</artifactId>
                        <version>1.3</version>
                        <exclusions>
                            <exclusion>
                                <groupId>org.codehaus.groovy</groupId>
                                <artifactId>groovy-all</artifactId>
                            </exclusion>
                        </exclusions>
                    </dependency>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-all</artifactId>
                        <version>1.7.5</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.spockframework</groupId>
                <artifactId>spock-maven</artifactId>
                <version>${spock.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>find-specs</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-core</artifactId>
            <version>${spock.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Notice we must add the gmaven-plugin and spock-maven plugin to the plugins section. We must also add the spock-core dependency to our project. This is all we need to do to be able to run Spock specifications with Maven. But we need to do some extra steps to be able to run our Spock specifications from SpringSource Tool Suite.

First we add the directory src/test/groovy (which is used to save the Spock specifications in) to our project. Then we assign this new directory as source directory to the project. We open the properties of our project and select Java Build Path:

Next we click on the Add Folder... button and select the Create New Folder... button. We create the folder src/test/groovy:

We click on the Finish button and now we can select the newly created folder as a new source folder:

Now comes an important step, because we must change the Output folder of our newly created source folder. We select it and press the Edit... button. In the dialog window we select the radio button Specific output folder and fill in target/test-classes. If we don't change the output folder then STS cannot determine changes in the sources if we use the Run As | JUnit Test action.

Now we have added a new source folder to our project and assigned a correct output folder for the compiled class files:

Next we must make our Java project a Groovy project in STS. We right-click on our project and select Configure | Convert to Groovy Project:

Okay, STS is now ready for our Spock specifications! We write the following specification and save it as src/test/groovy/com/mrhaki/app/services/UserServiceImplSpec.groovy:

package com.mrhaki.app.services

import spock.lang.Specification

class UserServiceImplSpec extends Specification {
    
    UserServiceImpl userService = new UserServiceImpl();
    
    def "Search for existing name must return correct username"() {
        expect:
            userService.findUsername("Hubert A. Klein Ikkink") == 'mrhaki'
    }
    
    def "Search for non-existing name must return an empty String"() {
        expect:
            userService.findUsername('non-existing name') == ''
    }
    
    def "Search with null value for name must return an empty String"() {
        expect:
            userService.findUsername(null) == ''
    }
    
}

We can run our Spock specification with the Run or Run As | JUnit Test commands. STS recognizes the Spock specification as JUnit test and uses the testrunner to run our specification:

If the Run As command doesn't recognize the Spock specification as JUnit test then closing and reopening the source file may help.