Loading...

Thursday, May 23, 2013

Gr8Conf 2013 Europe Conference Report: University Day

The day started out cloudly and with a lot of rain. Fortunately the rain stopped during the day and for the next few days it should stay dry. This makes the walks to and from the hotel more comfortable. After registration there was some sweet pastry and drinks. For me the day started with presenting Getting Groovy, a beginner workshop for working with Groovy. It was nice to see people get there first contact with Groovy through Gradle and Spock on their Java projects. The presentation and notes are available online.

After a good lunch I went to the GPars workshop presented by Rusell Winder and Václav Pech. This is a topic I wanted to get my hands on for a longer time and this time I really could. Russel and Václav covered threads, agents, fork/join, parallel collections, data flow and actors. All backed by exercises we could do to use GPars for real. This was really good and also why I enjoy the conference, because you can use this time to really play around with gr8 technologies. The session was packed with information, hands-on exercises and really fun to follow.

And this was my lucky day, because the next workshop was about Unleashing the power of AST transformations. Another topic I really want to work with, but didn't have the time yet to get started. The workshop was presented by Andres Almiray and Cédric Champeau. Andres started out by an introduction to AST and his personal experience when he started to write his first transformations. Although it might look a bit intimidating writing AST transformation is something to start doing and then you probably won't stop. After the introduction it was time to open IntelliJ IDEA and work on the exercises and start writing AST transformations for real. This was great and really inspired me to start using this on my own projects. Cédric and Andres also gave some very useful tips for developing and testing transformations.

Directly after the last session it was time for pizza and soda. These were arranged by Canoo as part of Hackergarten on tour. During Hackergarten we should have fun, learn and work on some open source projects. Anders made a list of suggestions of things to work on and then the crowd was divided in small teams to work on tasks. The goal of Hackergarten is also to choose tasks that can be handled in a 2-3 hour time period, so at the end of the session code can be really committed back to the open source project. The good thing about Gr8Conf is that almost all project leads of those project are here, so changes can be done directly. I worked with Dierk Köning on fixing and cleaning up some of the tests and code of Open Dolphin. This was really fun to do and he also gave me some useful tips on using IntelliJ IDEA and vice versa. We were able to push fixes into the repository and at the end of the evening we achieved a 100% statement coverage again.

So this day was packed with a lot of information and was really fun. I am ready for the next day.

Friday, 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

Thursday, May 16, 2013

Grails Goodness: Checking Results from Forward Action in Controller Unit Tests

In Grails we can write unit tests for controllers. We can check for example the results from a redirect() or render() method. To check the result from a forward() action we can use the forwardedUrl property of the mock response object. The format of the URL is very basic and has the following form: /grails/(controller)/(action).dispatch?(queryParameters). So we get the servlet representation of a Grails controller request. We can use this format to check if our forward() method is correct in the unit test.

First we create a simple controller with a index() action which invokes the forward() method with a action and parameters:

package com.mrhaki.grails

class BookController {

    def index() {
        forward action: 'show', params: [fromIndex: true, bookId: 200]
    }

}

Now we write a test (with Spock of course) to check the values from the forward() method in the mock response. The following specification contains code to parse the forwardedUrl property. We get the /controller/action as String and the parameters as Map object. Using Groovy syntax we can check for the values with forwardedUrl and forwardedParams:

package com.mrhaki.grails

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(BookController)
class BookControllerSpecification extends Specification {

    def "index must forward to show action"() {
        when:
        controller.index()

        then:
        forwardedUrl == '/book/show'
    }

    def "index must set parameter fromIndex to value true and forward"() {
        when:
        controller.index()

        then:
        forwardedParams.fromIndex == 'true'
    }

    def "index must set parameter bookId to 200 and forward"() {
        when:
        controller.index()

        then:
        forwardedParams.bookId == '200'
    }

    private getForwardedParams() {
        parseResponseForwardedUrl()[1]
    }

    private String getForwardedUrl() {
        parseResponseForwardedUrl()[0]
    }

    private parseResponseForwardedUrl() {
        // Pattern for forwardedUrl stored in response.
        def forwardedUrlPattern = ~/\/grails\/(.*)?\.dispatch\?*(.*)/

        // Match forwardedUrl in response with pattern.
        def matcher = response.forwardedUrl =~ forwardedUrlPattern

        def forwardUrl = null
        def forwardParameters = [:]

        if (matcher) {
            // Url is first group in pattern. We add '/' so it has the same format as redirectedUrl from response.
            forwardUrl = "/${matcher[0][1]}"

            // Parse parameters that are available in the forwardedUrl of the response.
            forwardParameters = parseResponseForwardedParams(matcher[0][2])
        }

        [forwardUrl, forwardParameters]
    }

    private parseResponseForwardedParams(final String queryString) {
        // Query string has format paramName=paramValue¶m2Name=param2Value. & is optional.
        def parameters = queryString.split('&')

        // Turn the paramName=paramValue parts into a Map.
        def forwardParameters = parameters.inject([:]) { result, parameter ->
            def (parameterName, parameterValue) = parameter.split('=')
            result[parameterName] = parameterValue
            result
        }
        forwardParameters
    }
}

Code written with Grails 2.2.2 and Spock 0.7-groovy-2.0

Tuesday, May 14, 2013

Grails Goodness: Passing Objects to Attributes of Tags in Unit Tests

Unit testing tag libraries in Grails is easy. We can use the applyTemplate() method to execute a tag and check the output. We pass the HTML string representing the tag to applyTemplate() as we would use it in a GSP. Attribute values of a tag can be String values, but also any other type. To pass other types in our test as attribute values we must add an extra argument to applyTemplate(). The argument is a Map with model values which are used to pass as value to the tag library attributes.

Let's see this in action with an example. First we create a tag library with a tag that will show the value of the title property of a Book instance. The Book instance is passed to the tag as attribute value for the attribute book:

package com.mrhaki.grails

class BookTagLib {

    static namespace = 'book'

    def title = { attributes, body ->
        final Book book = attributes.get('book')
        final String bookTitle = book.title
        out << bookTitle
    }

}

We can test this tag with the following Spock specification. Notice we use the applyTemplate() method and pass an instance of Book using a Map as the second argument:

package com.mrhaki.grails

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(BookTagLib)
class BookTagLibSpecification extends Specification {

    def "show book title for given Book instance"() {
        given:
        final Book book = new Book(title: 'Gradle Effective Implementation Guide')

        expect:
        applyTemplate('<book:title book="${bookInstance}"/>', [bookInstance: book]) == 'Gradle Effective Implementation Guide'
    }

}

Code written with Grails 2.2.2 and Spock 0.7-groovy-2.0.

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

Monday, May 13, 2013

Grails Goodness: Testing Views and Templates

Grails has great support for testing. We can unit test controllers, taglibs, services and much more. One of the things we can unit test are views and templates. Suppose we have a view or template with some (hopefully simple) logic (a view/template should not contain complex logic), for example an if-else statement to display some content conditionally. We can write a test in Grails to see if the logic is correctly implemented.

Let's first create a template in our Grails application:

%{-- File: /grails-app/views/sample/_header.gsp --}%
<g:if test="${username}">
    <h1>Hi, ${username}</h1>
</g:if>
<g:else>
    <h1>Welcome</h1>
</g:else>

The template checks if there is a username attribute and shows the value is there is, otherwise a simple "Welcome" message is shown.

We can test this with the following Spock specification. We use Spock for writing the test, because it makes writing tests so much easier and more fun! We must make sure we use the GroovyPageUnitTestMixin, because this will add a render() method to our tests. The render() method accepts a Map arguments where we can set the template or view and optionally the model with attributes.

// File: test/unit/com/mrhaki/grails/views/HeaderTemplateSpecification.groovy
package com.mrhaki.grails.views

import grails.test.mixin.TestMixin
import grails.test.mixin.web.GroovyPageUnitTestMixin
import spock.lang.Specification

@TestMixin(GroovyPageUnitTestMixin)
class HeaderTemplateSpecification extends Specification {

    def "if username is set then show message Hi with username"() {
        expect: 'Template output must contain Hi, mrhaki'
        renderTemplateWithModel([username: 'mrhaki']).contains 'Hi, mrhaki'
    }

    def "if username is not set then show message Welcome"() {
        expect: 'Template output must contain Welcome'
        renderTemplateWithModel().contains 'Welcome'
    }

    private renderTemplateWithModel(model = [:]) {
        render(template: '/sample/header', model: model)
    }

}

Let's also write a simple Grails view GSP, which shows a list of items if items are set or otherwise show a message using the <g:message/> tag.

%{--File: grails-app/views/sample/items.gsp--}%
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>Simple GSP page</title></head>
<body>
<g:if test="${items}">
    <ul>
        <g:each in="${items}" var="item">
            <li>${item}</li>
        </g:each>
    </ul>
</g:if>
<g:else>
    <g:message code="noitems"/>
</g:else>
</body>
</html>

The following specification will check the output dependent on if there are elements in the model attribute items. Because we use GroovyPageUnitTestMixin we have access to a messageSource object where we can define values for keys that are used by the <g:message/> tag.

// File: test/unit/com/mrhaki/grails/views/ItemsViewSpecification.groovy
package com.mrhaki.grails.views

import grails.test.mixin.TestMixin
import grails.test.mixin.web.GroovyPageUnitTestMixin
import spock.lang.Specification

@TestMixin(GroovyPageUnitTestMixin)
class ItemsViewSpecification extends Specification {

    def "if items are available then show items as list items"() {
        when:
        final String output = renderViewWithItems(['one'])

        then:
        output.contains '
  • one
  • ' } def "if collection of items is empty then show message items are empty"() { given: messageSource.addMessage 'noitems', request.locale, 'NO_ITEMS' when: final String output = renderViewWithItems() then: output.contains 'NO_ITEMS' } private renderViewWithItems(items = []) { render(view: '/sample/user', model: [items: items]) } }

    Code written with Grails 2.2.1

    Gradle Goodness: Running a Single Test

    We can run test code with Gradle using the test task that is added by the Java plugin. By default all tests found in the project are executed. If we want to run a single test we can use the Java system property test.single with the name of the test. Actually the pattern for the system property is taskName.single. The taskName is the name of the task of type Test in our project. We will see how we can use this in our builds.

    First we create a simple build.gradle file to run our tests:

    // File: build.gradle
    apply plugin: 'java'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testCompile 'junit:junit:[4,)'
    }
    
    test {
        testLogging {
            // Show that tests are run in the command-line output
            events 'started', 'passed'
        }
    }
    

    Next we create two test classes with each a single test method, just to demonstrate we can invoke them as single test later on.

    // File: src/test/java/com/mrhaki/gradle/SampleTest.java
    package com.mrhaki.gradle;
    
    import static org.junit.Assert.*;
    import org.junit.*;
    
    public class SampleTest {
    
        @Test public void sample() {
            assertEquals("Gradle is gr8", "Gradle is gr8");
        }
        
    }
    

    // File: src/test/java/com/mrhaki/gradle/AnotherSampleTest.java
    package com.mrhaki.gradle;
    
    import static org.junit.Assert.*;
    import org.junit.*;
    
    public class AnotherSampleTest {
    
        @Test public void anotherSample() {
            assertEquals("Gradle is great", "Gradle is great");
        }
    }
    

    To only run the SampleTest we must invoke the test task from the command-line with the Java system property -Dtest.single=Sample:

    $ gradle -Dtest.single=Sample test
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava
    :processTestResources UP-TO-DATE
    :testClasses
    :test
    
    com.mrhaki.gradle.SampleTest > sample STARTED
    
    com.mrhaki.gradle.SampleTest > sample PASSED
    
    BUILD SUCCESSFUL
    
    Total time: 11.404 secs
    

    Notice only one test is execute now. Gradle will get the value Sample and uses it in the following pattern **/<Java system property value=Sample>*.class to find the test class. So we don't have to type the full package and class name of our single test class. To only invoke the AnotherSampleTest test class we run the test task with a different value for the Java systme property:

    $ gradle -Dtest.single=AnotherSample test
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :test
    
    com.mrhaki.gradle.AnotherSampleTest > anotherSample STARTED
    
    com.mrhaki.gradle.AnotherSampleTest > anotherSample PASSED
    
    BUILD SUCCESSFUL
    
    Total time: 5.62 secs
    

    We can also use a pattern for the Java system property to run multiple tests that apply to the pattern. For example we can use *Sample to run both SampleTest and AnotherSampleTest:

    $ gradle -Dtest.single=*Sample test
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :test
    
    com.mrhaki.gradle.AnotherSampleTest > anotherSample STARTED
    
    com.mrhaki.gradle.AnotherSampleTest > anotherSample PASSED
    
    com.mrhaki.gradle.SampleTest > sample STARTED
    
    com.mrhaki.gradle.SampleTest > sample PASSED
    
    BUILD SUCCESSFUL
    
    Total time: 5.605 secs
    

    To show the Java system property also works for other tasks of type Test we add a new task to our build.gradle file. We name the task sampleTest and include our tests. We also apply the same testLogging now to all tasks with type Test so we can see the output.

    // File: build.gradle
    apply plugin: 'java'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testCompile 'junit:junit:[4,)'
    }
    
    task sampleTest(type: Test, dependsOn: testClasses) {
        include '**/*Sample*'
    }
    
    tasks.withType(Test) {
        testLogging {
            events 'started', 'passed'
        }
    }
    

    Next we want to run only the SampleTest class, but now we use the Java system property -DsampleTest.single=S*:

    $ gradle -DsampleTest.single=S* sampleTest
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava UP-TO-DATE
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :sampleTest
    
    com.mrhaki.gradle.SampleTest > sample STARTED
    
    com.mrhaki.gradle.SampleTest > sample PASSED
    
    BUILD SUCCESSFUL
    
    Total time: 10.677 secs
    

    Code written with Gradle 1.6

    Friday, May 10, 2013

    Gradle Goodness: Show More Information About Failed Tests

    Running tests in Gradle is easy. Normally if one of the tests fails the build fails as well. But we don't see immediately in the command-line output why a test fails. We must first open the generated HTML test report. But there are other ways as well.

    First we create the following sample Gradle build file:

    // File: build.gradle
    apply plugin: 'java'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testCompile 'junit:junit:[4,)'
    }
    

    And we use the following sample JUnit test class. Notice this test will always fail, which is what we want in this case.

    // File: src/test/java/com/mrhaki/gradle/SampleTest.java
    package com.mrhaki.gradle;
    
    import org.junit.*;
    
    public class SampleTest {
    
        @Test public void sample() {
            Assert.assertEquals("Gradle is gr8", "Gradle is great");
        }
        
    }
    

    To run our test we execute the test task. If we run the task we see in the output on which line the test fails, but we don't see the assertion why it went wrong:

    $ gradle test
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava
    :processTestResources UP-TO-DATE
    :testClasses
    :test
    
    com.mrhaki.gradle.SampleTest > sample FAILED
        org.junit.ComparisonFailure at SampleTest.java:8
    
    1 test completed, 1 failed
    :test FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':test'.
    > There were failing tests. See the report at: file:///Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/gradle/testlogging/build/reports/tests/index.html
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    
    Total time: 4.904 secs
    

    We can run the test task again, but now set the Gradle logging level to info with the command-line option -i or --info. Now we get the assertion about what went wrong in the output:

    $ gradle test -i
    Starting Build
    Settings evaluated using empty settings script.
    Projects loaded. Root project using build file 
    ...
    Successfully started process 'Gradle Worker 1'
    Gradle Worker 1 executing tests.
    Gradle Worker 1 finished executing tests.
    
    com.mrhaki.gradle.SampleTest > sample FAILED
        org.junit.ComparisonFailure: expected:<gradle is gr[8]> but was:<gradle is gr[eat]>
            at org.junit.Assert.assertEquals(Assert.java:115)
            at org.junit.Assert.assertEquals(Assert.java:144)
            at com.mrhaki.gradle.SampleTest.sample(SampleTest.java:8)
    Process 'Gradle Worker 1' finished with exit value 0 (state: SUCCEEDED)
    
    1 test completed, 1 failed
    Finished generating test XML results (0.025 secs)
    Generating HTML test report...
    Finished generating test html results (0.027 secs)
    :test FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':test'.
    > There were failing tests. See the report at: file:///Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/gradle/testlogging/build/reports/tests/index.html
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output.
    
    BUILD FAILED
    
    Total time: 5.117 secs
    

    But this still generates a lot of noise. It is better to customize the test logging by configuring the test task. We can configure the logging on different levels. To get the information about the failure we want we only have to change the exceptionFormat property and set the value to full. Our Gradle build file now looks like this:

    // File: build.gradle
    apply plugin: 'java'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testCompile 'junit:junit:[4,)'
    }
    
    test {
        testLogging {
            exceptionFormat = 'full'
        }
    }
    

    We can re-run the test task and use the normal logging level, but this time we also get the reason why our test fails, without the extra noise:

    $ gradle test
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava UP-TO-DATE
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :test
    
    com.mrhaki.gradle.SampleTest > sample FAILED
        org.junit.ComparisonFailure: expected:<gradle is gr[8]> but was:<gradle is gr[eat]>
            at org.junit.Assert.assertEquals(Assert.java:115)
            at org.junit.Assert.assertEquals(Assert.java:144)
            at com.mrhaki.gradle.SampleTest.sample(SampleTest.java:8)
    
    1 test completed, 1 failed
    :test FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':test'.
    > There were failing tests. See the report at: file:///Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/gradle/testlogging/build/reports/tests/index.html
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    
    Total time: 5.906 secs
    

    Sample written with Gradle 1.6