Search

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

May 12, 2016

Grails Goodness: Running Tests Continuously

When we write software it is good practice to also write tests. Either before writing actual code or after, we still need to write tests. In Grails we can use the test-app command to execute our tests. If we specify the extra option -continuous Grails will monitor the file system for changes in class files and automatically compiles the code and executes the tests again. This way we only have to start this command once and start writing our code with tests. If we save our files, our code gets compiled and tested automatically. We can see the output in the generated HTML report or on the console.

Suppose we have our Grails interactive shell open and we type the following command:

grails> test-app -continuous
| Started continuous test runner. Monitoring files for changes...
grails>

Written with Grails 3.1.6.

May 11, 2016

Grails Goodness: Use Random Server Port In Integration Tests

Because Grails 3 is based on Spring Boot we can use a lot of the functionality of Spring Boot in our Grails applications. For example we can start Grails 3 with a random available port number, which is useful in integration testing scenario's. To use a random port we must set the application property server.port to the value 0. If we want to use the random port number in our code we can access it via the @Value annotation with the expression ${local.server.port}.

Let's create a very simple controller with a corresponding integration test. The controller is called Sample:

// File: grails-app/controllers/mrhaki/SampleController.groovy
package mrhaki

class SampleController {

    def index() { 
        respond([message: 'Grails 3 is awesome!'])
    }
}

We write a Spock integration test that will start Grails and we use the HTTP Requests library to access the /sample endpoint of our application.

// File: src/integration-test/groovy/mrhaki/SampleControllerIntSpec.groovy
package mrhaki

import com.budjb.httprequests.HttpClient
import com.budjb.httprequests.HttpClientFactory
import grails.test.mixin.integration.Integration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import spock.lang.Specification

@Integration
class SampleControllerIntSpec extends Specification {
    
    /**
     * Server port configuration for Grails test 
     * environment is set to server.port = 0, which
     * means a random available port is used each time
     * the application starts.
     * The value for the port number is accessible
     * via ${local.server.port} in our integration test.
     */
    @Value('${local.server.port}')
    Integer serverPort

    /**
     * HTTP test client from the HTTP Requests library:
     * http://budjb.github.io/http-requests/latest
     */
    @Autowired
    HttpClientFactory httpClientFactory

    private HttpClient client

    def setup() {
        // Create HTTP client for testing controller.
        client = httpClientFactory.createHttpClient()
    }

    void "sample should return JSON response"() {
        when:
        // Nice DSL to build a request.
        def response = client.get {
            // Here we use the serverPort variable.
            uri = "http://localhost:${serverPort}/sample"
            accept = 'application/json'
        }
        
        then:
        response.status == 200
        
        and:
        final Map responseData = response.getEntity(Map)
        responseData.message == 'Grails 3 is awesome!'
    }
}

Finally we add the server.port to the application configuration:

# File: grails-app/conf/application.yml
...
environments:
    test:
        server:
            port: 0 # Random available port
...

Let's run the integration test: $ grails test-app mrhaki.SampleControllerIntSpec -integration. When we open the test report and look at the standard output we can see that a random port is used:

Written with Grails 3.1.6.

February 10, 2014

Grails Goodness: Run Forked Tests in IntelliJ IDEA

In the latest Grails releases we can execute our tests in so-called forked mode. This means a separate JVM is started with an isolated classpath from the Grails build system. When we want to run our tests in forked mode from within IntelliJ IDEA we get the following error: Error running forked test-app: Could not load grails build listener class (Use --stacktrace to see the full trace). To make running tests in forked mode work with IntelliJ IDEA we must add one of the IntelliJ IDEA supplied JAR files to the Grails classpath.

We need to search for the file grails-rt.jar in the directory where we installed IntelliJ IDEA. For example on Mac OSX this would be Applications/IntelliJ IDEA 13.app/plugins/Grails/lib/grails-rt.jar. We need to copy this file to the lib directory of our Grails project. On *nix systems we can actually define a soft link to this location in the lib directory. For example with the following command $ ln -s /Applications/IntelliJ\ IDEA\ 13.app/plugins/Grails/lib/grails-rt.jar lib/intellij-grails-rt.jar.

Now we can run our Grails forked tests from within IntelliJ IDEA. To debug our tests we must add the option --debug-fork to the Run Configuration of the test.

We could also disable the forked mode for tests to run them in IntelliJ IDEA. We must then set grails.project.fork.test = false in grails-app/conf/BuildConfig.groovy. In non-forked mode we don't need to copy the file grails-rt.jar.

Tested with IntelliJ IDEA 13 and Grails 2.3.5.

September 12, 2013

Grails Goodness: Unit Testing Render Templates from Controller

In a previous blog post we learned how we can unit test a template or view independently. But what if we want to unit test a controller that uses the render() method and a template with the template key instead of a view? Normally the view and model are stored in the modelAndView property of the response. We can even use shortcuts in our test code like view and model to check the result. But a render() method invocation with a template key will simply execute the template (also in test code) and the result is put in the response. With the text property of the response we can check the result.

In the following sample controller we use the header template and pass a username model property to render output.

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

class SampleController {

    def index() {
        render template: 'header', model: [username: params.username]
    }

}

With this Spock specification we test the index() action:

package com.mrhaki.grails.web

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

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "index action renders template with given username"() {
        given:
        params.username = username

        when:
        controller.index()

        then:
        response.text.trim() == expectedOutput

        where:
        username || expectedOutput
        'mrhaki' || '

Hi, mrhaki

' null || '

Welcome

' } }

Suppose we don't want to test the output of the actual template, but we only want to check in our test code that the correct template name is used and the model is correct. We can use the groovyPages or views properties in our test code to assign mock implementation for templates. The groovyPages or views are added by the ControllerUnitTestMixin class, which is done automatically if we use the @TestFor() annotation. The properties are maps where the keys are template locations and the values are strings with mock implementations for the template. For example the template location for our header template is /sample/_header.gsp. We can assign a mock String implementation with the following statement: views['/sample/_header.gsp'] = 'mock implementation'

We can rewrite the Spock specification and now use mock implementations for the header template. We can even use the model in our mock implementation, so we can check if our model is send correctly to the template.

package com.mrhaki.grails.web

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

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "index action renders mock template with given username"() {
        given:
        // Mock implementation with escaped $ (\$), because otherwise
        // the String is interpreted by Groovy as GString.
        groovyPages['/sample/_header.gsp'] = "username=\${username ?: 'empty'}"

        // Or we can use views property:
        //views['/sample/_header.gsp'] = "username=\${username ?: 'empty'}"

        and:
        params.username = username

        when:
        controller.index()

        then:
        response.text.trim() == expectedOutput

        where:
        username || expectedOutput
        'mrhaki' || 'username=mrhaki'
        null     || 'username=empty'
    }

}

Code written with Grails 2.2.4

August 19, 2013

Grails Goodness: Set Request Locale in Unit Tests

There is really no excuse to not write unit tests in Grails. The support for writing tests is excellent, also for testing code that has to deal with the locale set in a user's request. For example we could have a controller or taglib that needs to access the locale. In a unit test we can invoke the addPreferredLocale() method on the mocked request object and assign a locale. The code under test uses the custom locale we set via this method.

In the following controller we create a NumberFormat object based on the locale in the request.

package com.mrhaki.grails

import java.text.NumberFormat

class SampleController {

    def index() {
        final Float number = params.float('number')
        final NumberFormat formatter = NumberFormat.getInstance(request.locale)
        render formatter.format(number)
    }

}

If we write a unit test we must use the method addPreferredLocale() to simulate the locale set in the request. In the following unit test (written with Spock) we use this method to invoke the index() action of the SampleController:

package com.mrhaki.grails

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

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    @Unroll
    def "index must render formatted number for request locale #locale"() {
        given: 'Set parameter number with value 42.102'
        params.number = '42.102'

        and: 'Simulate locale in request'
        request.addPreferredLocale locale

        when: 'Invoke controller action'
        controller.index()

        then: 'Check response equals expected result'
        response.text == result

        where:
        locale           || result
        Locale.US        || '42.102'
        new Locale('nl') || '42,102'
        Locale.UK        || '42.102'
    }

}

Code written with Grails 2.2.4

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

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.

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/items', model: [items: items]) } }

    Code written with Grails 2.2.1

    May 7, 2010

    Grails Goodness: Using Codecs in Test Classes

    When we run Grails a lot of metaClass information is added to the classes of our application. This also include the support for encoding and decoding String values. For example in our Grails application we can use "<b>Grails</b>".encodeAsHTML() and we get "&lt;b&gt;Grails&lt;/b&gt;". But if we want to use the encodeAsHTML() method in our class we get an exception, because the method is not available. To make a Grails encoder/decoder available in our test class we must use the loadCodec() method. See the following example:

    package com.mrhaki.grails
    
    class HTMLCodecControllerTests extends grails.test.ControllerUnitTestCase {
        void testAction() {
            loadCodec HTMLCodec  // Now we can use encodeAsHTML, decodeAsHTML
            assertEquals "&lt;b&gt;Grails&lt;/b&gt;", '<b>Grails</b>'.encodeAsHTML()
        }
    }
    

    May 2, 2010

    Grails Goodness: Testing for Chain Result in Controller

    Testing a controller in Grails in easy with the ControllerUnitTestCase. If we extend our test class from the ControllerUnitTestCase we get a lot of extra functionality to write our tests. For example the controller is extended with a parameters map so we can set parameter values in our test case. Suppose we the following controller and want to test it:

    class SimpleController {
        def hello = {
            chain action: 'world', controller: 'other', model: [message: new Expando(text: params.msg)]
        }
    }
    

    By extending the ControllerUnitTestCase the mockController(SimpleController) method is invoked. This will add (among other things) the map chainArgs to the controller. The map is filled with the attributes of our chain() method. And we can use this map in our test to check for correct results:

    class SimpleControllerTests extends grails.test.ControllerUnitTestCase {
        void setUp() { super.setUp() }
    
        void testHelloAction() {
            controller.params.msg = 'Hello world'
            controller.hello()
            assertTrue 'world', controller.chainArgs.action
            assertTrue 'other', controller.chainArgs.controller
            assertTrue 'Hello world', controller.chainArgs.model.message.text
        }
    }
    

    April 21, 2010

    Grails Goodness: Cleaning Before Running Tests

    If we want to first clean our Grails project before we are running our test code we can pass the -clean argument. This way all source files will be recompiled so the tests are started from a clean slate.

    $ grails test-app -clean
    

    April 15, 2010

    Grails Goodness: Invoking a Single Test Method

    When we use $ grails test-app to test our code all tests are run. We can specify a single test class as an argument for the test-app script. So for example if we have a HelloWorldControllerTests class we use the following command $ grails test-app HelloWorldController. Grails supports wildcards for defining the test class, so we can also use $ grails test-app Hello* for example.

    But we can even specify the method in our HelloWorldControllerTests class we want to be tested. If the test class has the method testSayHello() we use the following command $ grails test-app HelloWorldController.sayHello and only the testSayHello().

    March 16, 2010

    Grails Goodness: See Test Output on the Command Line

    As from Grails 1.2 we can see the output from test scripts directly on the console. We must use the arguments -echoOut and -echoErr when we run the tests.

    $ grails test-app -echoOut -echoErr
    

    March 15, 2010

    Grails Goodness: Using MetaClass with Testing

    We can use the metaClass property of classes to define behavior we want to use in our tests. But if we do, the change is not only for the duration of a test method, but for the entire test run. This is because we make a change at class level and other tests that use the class will get the new added behavior. To limit our change to a test method we first use the registerMetaClass() method. Grails will remove our added behavior automatically after the test method is finished.

    Let's see this with an example. We have a domain class User which uses the Searchable plugin. This plugin will add a search() and we want to use in our test case.

    class User {
        static searchable = true
        String username
    }
    
    class UserTests extends GrailsUnitTestCase {
        void testSearch() {
            registerMetaClass User
            User.metaClass.static.search = { searchText ->
                [results: [new User(username:'mrhaki')],
                 total: 1, offset: 0, scores: [1]] 
            }
            assertEquals 'mrhaki', User.search('mrhaki').results[0].username
        }
    }