Thursday, July 9, 2015

Tutorial: Writing tests with Spock

Overview:
This article looks at how to use Spock for writing tests. It's a yet another awesome project from google code.

Why Spock? Read here.

For me, it's the simplicity, expressiveness and less code to write, which makes the tests clean. Also, in-built BDD notations such as given, when, then, where etc.

You can find the sample code for this application here.

Prerequisite:
To run the application, you need the following installed.
Basic understanding on Groovy
Java 8+
Maven 3

The pom.xml
 <?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/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan.blogger</groupId>  
   <artifactId>spock-sample</artifactId>  
   <version>1.0-SNAPSHOT</version>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-compiler-plugin</artifactId>  
         <version>${maven-compiler-plugin.version}</version>  
         <configuration>  
           <source>${jdk.version}</source>  
           <target>${jdk.version}</target>  
         </configuration>  
       </plugin>  
       <!-- Mandatory plugins for using Spock -->  
       <plugin>  
         <!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin -->  
         <groupId>org.codehaus.gmavenplus</groupId>  
         <artifactId>gmavenplus-plugin</artifactId>  
         <version>${gmavenplus-plugin.version}</version>  
         <executions>  
           <execution>  
             <goals>  
               <goal>compile</goal>  
               <goal>testCompile</goal>  
             </goals>  
           </execution>  
         </executions>  
       </plugin>  
       <!-- Only required if names of spec classes don't match default Surefire patterns (`*Test` etc.) -->  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-surefire-plugin</artifactId>  
         <version>${maven-surefire-plugin.version}</version>  
         <configuration>  
           <useFile>false</useFile>  
           <includes>  
             <include>**/*Spec.java</include>  
           </includes>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
   <dependencies>  
     <!-- Mandatory dependencies for using Spock -->  
     <dependency>  
       <groupId>org.spockframework</groupId>  
       <artifactId>spock-core</artifactId>  
       <version>${spock-core.version}</version>  
       <scope>test</scope>  
     </dependency>  
     <!-- Optional for using Spock -->  
     <!-- use a specific Groovy version rather than the one specified by spock-core -->  
     <dependency>  
       <groupId>org.codehaus.groovy</groupId>  
       <artifactId>groovy-all</artifactId>  
       <version>${groovy-all.version}</version>  
       <scope>test</scope>  
     </dependency>  
     <!--&lt;!&ndash; enables mocking of classes (in addition to interfaces) &ndash;&gt;-->  
     <!--<dependency>-->  
       <!--<groupId>cglib</groupId>-->  
       <!--<artifactId>cglib-nodep</artifactId>-->  
       <!--<version>${cglib-nodep.version}</version>-->  
       <!--<scope>test</scope>-->  
     <!--</dependency>-->  
     <!--&lt;!&ndash; enables mocking of classes without default constructor (together with CGLIB) &ndash;&gt;-->  
     <!--<dependency>-->  
       <!--<groupId>org.objenesis</groupId>-->  
       <!--<artifactId>objenesis</artifactId>-->  
       <!--<version>${objenesis.version}</version>-->  
       <!--<scope>test</scope>-->  
     <!--</dependency>-->  
   </dependencies>  
   <properties>  
     <gmavenplus-plugin.version>1.5</gmavenplus-plugin.version>  
     <maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>  
     <spock-core.version>1.0-groovy-2.4</spock-core.version>  
     <groovy-all.version>2.4.3</groovy-all.version>  
     <cglib-nodep.version>3.1</cglib-nodep.version>  
     <objenesis.version>2.1</objenesis.version>  
     <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>  
     <jdk.version>1.8</jdk.version>  
   </properties>  
 </project>  

Writing the test

package org.fazlan.blogger.sample

import spock.lang.Specification


class SimpleCalculatorSpec extends Specification {

    Calculator calculator

    def setup() {
        calculator = new SimpleCalculator()
    }

    def "adds numbers and returns the sum of the numbers"() {

        when:
        def result = calculator.add(* numbers)

        then:
        result == expected_result

        where:
        numbers    | expected_result
        [0]        | 0
        [1]        | 1
        [1.4, 2.5] | 3.9
    }

    def "multiplies given numbers and returns the multiplication result"() {

        when:
        def result = calculator.multiply(* numbers)

        then:
        result == expected_result

        where:
        numbers  | expected_result
        [0]      | 0
        [1]      | 1
        [1, 0]   | 0
        [1.5, 2] | 3
    }
}

As seen above, it uses less code and no configuration compared to frameworks like cucumber-jvm or jBehave.

Summary
This article looks at how to use Spock for writing tests.

You can find the sample code for this application here.