Search

Dark theme | Light theme
Showing posts with label Testing. Show all posts
Showing posts with label Testing. Show all posts

August 22, 2013

Spocklight: Using the Old Method

Spock has some great features to write specifications or tests that are short and compact. One of them is the old() method. The old() method can only be used in a then: block. With this method we get the value a statement had before the when: block is executed.

Let's see this with a simple example. In the following specification we create a StringBuilder with an initial value. In the then: block we use the same initial value for the assertion:

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"() {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue

        then:
        builder.toString() == 'Spock ' + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

If we want to change the initial value when we create the StringBuilder we must also change the assertion. We can refactor the feature method and show our intention of the specification better. We add the variable oldToString right after we have created the StringBuilder. We use this in the assertion.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"() {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')
        final String oldToString = builder.toString()

        when:
        builder << appendValue

        then:
        builder.toString() == oldToString + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

But with Spock we can do one better. Instead of creating an extra variable we can use the old() method. In the assertion we replace the variable reference oldToString with old(builder.toString()). This actually means we want the value for builder.toString() BEFORE the when: block is executed. The assertion also is now very clear and readable and the intentions of the specification are very clear.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"() {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue

        then:
        builder.toString() == old(builder.toString()) + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

Let's change the specification a bit so we get some failures. Instead of adding the appendValue data variable unchanged to the StringBuilder we want to add a capitalized value.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"() {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue.capitalize()

        then:
        builder.toString() == old(builder.toString()) + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

If we run the specification we get assertion failures. In the following output we see such a failure and notice the value for the old() is shown correctly:

Condition not satisfied:

builder.toString() == old(builder.toString()) + appendValue
|       |          |  |                       | |
|       |          |  Spock                   | rocks!
|       |          |                          Spock rocks!
|       |          false
|       |          1 difference (91% similarity)
|       |          Spock (R)ocks!
|       |          Spock (r)ocks!
|       Spock Rocks!
Spock Rocks!

Note: If we use the old() method we might get an InternalSpockError exception when assertions fail. The error looks something like: org.spockframework.util.InternalSpockError: Missing value for expression "...". Re-ordering the assertion can help solve this. For example putting the old() method statement last. In Spock 1.0-SNAPSHOT this error doesn't occur.

For more information we can read Rob Fletcher's blog post about the old() method.

Code written with Spock 0.7-groovy-2.0.

May 17, 2013

Spocklight: Writing Assertions for Arguments Mock Methods

My colleague Arthur Arts has written a blog post Tasty Test Tip: Using ArgumentCaptor for generic collections with Mockito. This inspired me to do the same in Spock. With the ArgumentCaptor in Mockito the parameters of a method call to a mock are captured and can be verified with assertions. In Spock we can also get a hold on the arguments that are passed to method call of a mock and we can write assertions to check the parameters for certain conditions.

When we create a mock in Spock and invoke a method on the mock the arguments are matched using the equals() implementation of the argument type. If they are not equal Spock will tell us by showing a message that there are too few invocations of the method call. Let's show this with an example. First we create some classes we want to test:

package com.mrhaki.spock

public class ClassUnderTest {

    private final Greeting greeting

    ClassUnderTest(final Greeting greeting) {
        this.greeting = greeting
    }

    String greeting(final List<Person> people) {
        greeting.sayHello(people)
    }
}
package com.mrhaki.spock

interface Greeting {
    String sayHello(final List<Person> people)
}
package com.mrhaki.spock

@groovy.transform.Canonical
class Person {
    String name
}    

Now we can write a Spock specification to test ClassUnderTest. We will now use the default matching of arguments of a mock provided by Spock.

package com.mrhaki.spock

import spock.lang.Specification

class SampleSpecification extends Specification {

    final ClassUnderTest classUnderTest = new ClassUnderTest()

    def "check sayHello is invoked with people in greeting method"() {
        given:
        final Greeting greeting = Mock()
        classUnderTest.greeting = greeting

        and:
        final List<Person> people = ['mrhakis', 'hubert'].collect { new Person(name: it) }

        when:
        final String greetingResult = classUnderTest.greeting(people)

        then:
        1 * greeting.sayHello([new Person(name: 'mrhaki'), new Person(name: 'hubert')])
    }

}

When we execute the specification we get a failure with the message that there are too few invocations:

...
Too few invocations for:

1 * greeting.sayHello([new Person(name: 'mrhaki'), new Person(name: 'hubert')])   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * greeting.sayHello([com.jdriven.spock.Person(mrhakis), com.jdriven.spock.Person(hubert)])
...

To capture the arguments we have to use a different syntax for the method invocation on the mock. This time we define the method can be invoked with any number of arguments ((*_)) and then use a closure to capture the arguments. The arguments are passed to the closure as a list. We can then get the argument we want and write an assert statement.

package com.mrhaki.spock

import spock.lang.Specification

class SampleSpecification extends Specification {

    final ClassUnderTest classUnderTest = new ClassUnderTest()

    def "check sayHello is invoked with people in greeting method"() {
        given:
        final Greeting greeting = Mock()
        classUnderTest.greeting = greeting

        and:
        final List<Person> people = ['mrhakis', 'hubert'].collect { new Person(name: it) }

        when:
        final String greetingResult = classUnderTest.greeting(people)

        then:
        1 * greeting.sayHello(*_) >> { arguments ->
            final List<Person> argumentPeople = arguments[0]
            assert argumentPeople == [new Person(name: 'mrhaki'), new Person(name: 'hubert')]
        }
    }

}

We run the specification again and it will fail again (of course), but this time we get an assertion message:

...
Condition not satisfied:

argumentPeople == [new Person(name: 'mrhaki'), new Person(name: 'hubert')]
|              |   |                           |
|              |   |                           com.jdriven.spock.Person(hubert)
|              |   com.jdriven.spock.Person(mrhaki)
|              false
[com.jdriven.spock.Person(mrhakis), com.jdriven.spock.Person(hubert)]

    at com.jdriven.spock.SampleSpecification.check sayHello is invoked with people in greeting method_closure2(SampleSpecification.groovy:25)
...

Code written with Spock 0.7-groovy-2.0

Spocklight: Change Return Value of Mocked or Stubbed Service Based On Argument Value

My colleague Albert van Veen wrote a blog post about Using ArgumentMatchers with Mockito. The idea is to let a mocked or stubbed service return a different value based on the argument passed into the service. This is inspired me to write the same sample with Spock.

Spock already has built-in mock and stub support, so first of all we don’t need an extra library to support mocking and stubbing. We can easily create a mock or stub with the Mock() and Stub() methods. We will see usage of both in the following examples.

In the first example we simply return true or false for ChocolateService.doesCustomerLikesChocolate() in the separate test methods.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private ChocolateService chocolateService = Mock()
    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = chocolateService
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')

        and: 'Mock returns true'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> true
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')

        and: 'Mock returns false'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> false
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

In the following example we mimic the ArgumentMatcher and this time we use a stub instead of mock.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = Stub(ChocolateService) {
            getCandiesLikeByCustomer(_) >> { Customer customer ->
                customer?.firstName == 'Albert'
            }
        }
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

Code written with Spock 0.7-groovy-2.0

May 14, 2013

Spocklight: Using a Custom Hamcrest Matcher

In a previous blog post we learned how we can use Hamcrest matchers. We can also create a custom matcher and use it in our Spock specification. Let's create a custom matcher that will check if elements in a list are part of a range.

In the following specification we create the method inRange() which will return an instance of a Matcher object. This object must implement a matches() method and extra methods to format the description when the matcher fails. We use Groovy's support to create a Map and turn it into an instance of BaseMatcher.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*
import org.hamcrest.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of custom hamcrest matcher"() {
        given:
        final list = [2,3,4]

        expect:
        that list, inRange(0..10)
        that list, not(inRange(0..3))
    }

    /**
     * Create custom Hamcrest matcher to check if a list has elements
     * that are contained in the define range.
     *
     * @param range Range to check if elements in the list are in this range.
     * @return Hamcrest matcher to check if elements in the list are part of the range.
     */
    private inRange(final range) {
        [
            matches: { list -> range.intersect(list) == list },
            describeTo: { description ->
                description.appendText("list be in range ${range}")
            },
            describeMismatch: { list, description ->
                description.appendValue(list.toListString()).appendText(" was not in range ${range}")
            }
        ] as BaseMatcher
    }

}

We can run the specification ($ groovy SampleSpecification.groovy) and everything should work and all tests must pass.

We change the code to see the description we have added. So we change that list, inRange(0..10) to that list, inRange(0..3). We run the specification again ($ groovy SampleSpecification.groovy) and look at the output:

JUnit 4 Runner, Tests: 1, Failures: 1, Time: 200
Test Failure: sample usage of custom hamcrest matcher(com.mrhaki.spock.SampleSpecification)
Condition not satisfied:

that list, inRange(0..3)
|    |
|    [2, 3, 4]
false

Expected: list be in range [0, 1, 2, 3]
     but: "[2, 3, 4]" was not in range [0, 1, 2, 3]

    at com.mrhaki.spock.SampleSpecification.sample usage of custom hamcrest matcher(SampleSpecification.groovy:18)

Notice the output shows the text we have defined in the describeTo() and describeMismatch() methods.

Code written with Spock 0.7-groovy-0.2.

Spocklight: Support for Hamcrest Matchers

Spock has support for Hamcrest matchers and adds some extra syntactic sugar. In an expect: block in a Spock specification method we can use the following syntax value Matcher. Let's create a sample Spock specification and use this syntax with the Hamcrest matcher hasKey:

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        given:
        final sampleMap = [name: 'mrhaki']

        expect:
        sampleMap hasKey('name')
        sampleMap not(hasKey('name')) // To show assertion message.
    }

}

We can run the code ($groovy SampleSpecification.groovy) and see in the output a very useful assertion message for the second matcher in the expect: block. We directly see what went wrong and what was expected.

$ groovy SampleSpecification.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 210
Test Failure: sample usage of hamcrest matcher hasKey(com.mrhaki.spock.SampleSpecification)
Condition not satisfied:

sampleMap not(hasKey('name'))
|         |
|         false
[name:mrhaki]

Expected: not map containing ["name"->ANYTHING]
     but: was <{name=mrhaki}>

 at com.mrhaki.spock.SampleSpecification.sample usage of hamcrest matcher hasKey(SampleSpecification.groovy:18)

With Spock we can rewrite the specification and use the static method that() in spock.util.matcher.HamcrestSupport as a shortcut for the Hamcrest assertThat() method. The following sample shows how we can use that(). With this method we can use the assertion outside an expect: or then: block.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        given:
        final sampleMap = [name: 'mrhaki']

        expect:
        that sampleMap, hasKey('name')
    }

}

Finally we can use the expect() method in spock.util.matcher.HamcrestSupport to add the assertion in a then: block. This improves readability of our specification.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        when:
        final sampleMap = [name: 'mrhaki']

        then:
        expect sampleMap, hasKey('name')
    }

}

Code written with Spock 0.7-groovy-2.0

April 14, 2013

IntelliJ IDEA Knows How to Format Spock where: Blocks

IntelliJ IDEA keeps amazing me. Last week I learned the code formatter of IntelliJ IDEA 12 supports Spock specific where: block formatting. Spock has great a great feature called data tables. We can define a fixed set of data values in a table-like format where cells are separated with pipe (|) symbols. These tables are easiest to read if formatted in fixed size columns. The IntelliJ IDEA formatter will do this for us automatically.

Look at the following source code with a data table just typed with pipe symbols as separators, but not clearly formatted in fixed size columns:


If we run the code reformat command with Cmd+Alt+L (Windows/Linux: Ctrl+Alt+L) or use the menu option Code | Reformat Code... we get a dialog and select Run button to format the code:


The result is that our data table in the where: block is now correctly formatted:


Example with IntelliJ IDEA 12.1

September 15, 2010

Private Spring Dependency Injections for Unit Testing

If we want to unit test a Spring managed bean with a private field that is annotated with for example the @Autowired annotation, we must do something special. Normally we cannot access the private field to assign for example a stub implementation for testing, because we have to use the public setter method. But Spring allows the use of the @Autowired annotation on a private field. And that means we don't have a public setter method. We must use org.springframework.test.util.ReflectionTestUtils.setField() to assign a new value to the field. We pass the object which contains the private field, the field name and value to the method and our value is assigned to the private variable. So we can use this method to assign a stub implementation to the field and use it for testing.

// Class to test: src/main/java/com/mrhaki/spring/MyService.java
package com.mrhaki.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired
    private MessageService messageService;

    public String say(String name) {
        return messageService.getMessage() + name;
    }
}
// Support class used in MyService: src/main/java/com/mrhaki/spring/MessageService.java
package com.mrhaki.spring;

import org.springframework.stereotype.Component;

@Component
public class MessageService {
    public String getMessage() {
        return "Hello, ";
    }
}

We want to unit test MyService and provide a mock implementation for MessageService, so we only test the code in MyService. We use Mockito to provide the mock functionality. And because messageService is a private field we must use ReflectionTestUtils.setField() method.

// Test class for testing MyService: src/test/java/com/mrhaki/spring/MyServiceTest.java
package com.mrhaki.spring;

import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MyServiceTest {
    @Test
    public void sayHi() {
        MessageService messageService = mock(MessageService.class);
        when(messageService.getMessage()).thenReturn("Hi, ");

        MyService myService = new MyService();
        // Inject mock into private field:
        ReflectionTestUtils.setField(myService, "messageService", messageService);

        assertEquals("Hi, mrhaki", myService.say("mrhaki"));
    }
}

As a bonus we can use the following Gradle build script to compile and test these classes:

apply plugin: 'java'

repositories {
  mavenCentral()
}

dependencies {
  compile 'org.springframework:spring-context:3.0.4.RELEASE'
  testCompile 'junit:junit:4.8.1', 'org.mockito:mockito-all:1.8.5', 'org.springframework:spring-test:3.0.4.RELEASE'
}

Project is also available on GitHub: BlogSamples/SpringTestInjection.

June 29, 2010

Spocklight: Introduction to Spock Testing

In this blog entry we will start with a simple Spock specification for a Groovy class we create. We can learn why to use Spock on the Spock website. In this article we show with code how our tests will work with Spock. To get started with this sample we need Gradle installed on our machine and nothing else. The current release of Gradle at the time of writing this entry is 0.9-preview-3.

First we need to create a new directory for our little project and then we create a new build.gradle file:

$ mkdir spock-intro
$ cd spock-intro
$ mkdir -p src/main/groovy/com/mrhaki/blog src/test/groovy/com/mrhaki/blog
// File: build.gradle
apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    groovy 'org.codehaus.groovy:groovy:1.7.3'
    testCompile 'org.spockframework:spock-core:0.4-groovy-1.7'
}

Next we create our tests, but in Spock they are called specifications. We only need to extend the spock.lang.Specification and we get all the Spock magic in our hands. We start simple by defining a specification where we want to count the number of users in a UserService class. We are going to create the UserService class later, we start first with our specification:

package com.mrhaki.blog

import spock.lang.Specification

class UserServiceSpecification extends Specification {

    def "Return total number of users"() {
        setup: 'Create UserService instance with 2 users'
        UserService userService = new UserService(users: ['mrhaki', 'hubert'])

        expect: 'Invoke count() method'
        2 == userService.count()
    }

}

Notice at line 6 how we can use very descriptive method names by using String literals. Next we create an instance of the UserService class and pass a list of two users at line 8. And then we check if the return value is the expected value 2 with a simple assertion statement. Spock provides a very readable way to write code. Mostly we first setup code for testing, run the code and finally test the results. This logic is supported nicely by Spock by using the labels setup and expect. Later on we see more of these labels.

Before we run the test we create our UserService class:

package com.mrhaki.blog

class UserService {

    Collection<String> users

    int count() {
        users ? users.size() : 0
    }

}

We can run our code and test with the following command:

$ gradle test
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:compileTestJava
:compileTestGroovy
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 12.475 secs

The source files are compiled and our specification is run. We get the BUILD SUCCESSFUL message indicating our test runs fine. If the test would fail we can open build/reports/tests/index.html or build/test-results/TEST-com.mrhaki.blog.UserServiceSpecification.xml to see the failure.

We specified the count() method must return the number of users, but we only check it for 2 elements, but what if we want to test to see if 0 and 1 user also return the correct count value? We can create new methods in our specification class, but Spock makes it so easy to do this elegantly:

package com.mrhaki.blog

import spock.lang.Specification

class UserServiceSpecification extends Specification {

    def "Return total number of users"() {
        setup: 'Create UserService instance with users'
        UserService userService = new UserService(users: userList)

        expect: 'Invoke count() method'
        expectedCount == userService.count()

        where:
        expectedCount   | userList
        0               | null
        0               | []
        1               | ['mrhaki']
        2               | ['mrhaki', 'hubert']
    }

}

So what happens here? We use a new label where which contains a data table. Each row of the data table represent a new test run with the data from the row. In the setup block we used an unbound variable userList and in the expect block the unbound variable expectedCount. The variables get their values from the data table rows in the where block. So the first run the UserService instances gets null assigned to the users property and we expect the value 0 to be returned by the count() method. In the second run we pass an empty list and expect also 0 from the count() method. We have four rows, so our test is run four times when we invoke $ gradle test.

We can make the fact that four tests are run explicit by using the @Unroll annotation. We can use a String as argument describing the specific variable values used in a run. If we use the # followed by the unbound variable name will it be replaced when we run the code:

package com.mrhaki.blog

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

class UserServiceSpecification extends Specification {

    @Unroll("Expect to count #expectedCount users for following list #userList")
    def "Return total number of users"() {
        setup: 'Create UserService instance with users'
        UserService userService = new UserService(users: userList)

        expect: 'Invoke count() method'
        expectedCount == userService.count()

        where:
        expectedCount   | userList
        0               | null
        0               | []
        1               | ['mrhaki']
        2               | ['mrhaki', 'hubert']
    }

}

The generated XML with the test result contains the four runs with their specific names:

<?xml version="1.0" encoding="UTF-8"?>
<testsuite errors="0" failures="0" hostname="ci-test" name="com.mrhaki.blog.UserServiceSpecification" tests="4" time="0.707" timestamp="2010-06-29T18:17:24">
  <properties />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users for following list null" time="0.152" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users for following list []" time="0.027" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 1 users for following list [mrhaki]" time="0.0050" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 2 users for following list [mrhaki, hubert]" time="0.0010" />
  <system-out><![CDATA[]]></system-out>
  <system-err><![CDATA[]]></system-err>
</testsuite>

This concludes the introduction to Spock testing. In the future we learn more about Spock and the great features it provide to make writing tests easy and fun.