Testing
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
Code written with Grails 1.2.1.
Original blog post written on March 16, 2010.
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().
Code written with Grails 1.2.
Original blog post written on April 15, 2010.
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
Code written with Grails 1.2.
Original blog post written on April 21, 2010.
Rerun the Latest Failed Test
We can test our Grails application with $ grails test-app. But if one or more test fail we can easily rerun only the failed tests with the following command:
$ grails test-app -rerun
Code written with Grails 1.2.
Original blog post written on January 21, 2010.
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.
Original blog post written on May 12, 2016.
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
}
}
Code written with Grails 1.2.2.
Original blog post written on May 02, 2010.
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
Original blog post written on May 16, 2013.
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 "<b>Grails</b>". 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 "<b>Grails</b>", '<b>Grails</b>'.encodeAsHTML()
}
}
Code written with Grails 1.2.2.
Original blog post written on May 07, 2010.
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' || '<h1>Hi, mrhaki</h1>'
null || '<h1>Welcome</h1>'
}
}
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
Original blog post written on September 12, 2013.
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 '
<li>one</li>
'
}
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
Original blog post written on May 13, 2013.
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.
Original blog post written on May 14, 2013.
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.
// File: grails-app/controllers/com/mrhaki/grails/SampleController.groovy
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:
// File: test/unit/com/mrhaki/grails/SampleControllerSpec.groovy
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
Original blog post written on August 19, 2013.
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
}
}
Code written with Grails 1.2.1.
Original blog post written on March 15, 2010.
Mocking the Configuration in Unit Tests
When we write a unit test for our Grails service and in the service we use ConfigurationHolder.config to get the Grails configuration we get null for the config object when we run the unit test. Which is fine for a unit test, because we want to provide values for the configuration in our test. This is easy to do: we use the mockConfig method to set configuration values for the unit test. The method accepts a String that is a configuration script.
// File: grails-app/services/SimpleService.groovy
import org.codehaus.groovy.grails.common.ConfigurationHolder as GrailsConfig
class SimpleService {
String say(text) {
"$GrailsConfig.config.simple.greeting $text"
}
String sayConfig() {
say(GrailsConfig.config.simple.text)
}
}
// File: test/unit/SimpleServiceTests.groovy
import grails.test.*
class SimpleServiceTests extends GrailsUnitTestCase {
def service
protected void setUp() {
super.setUp()
service = new SimpleService()
mockConfig('''
simple {
greeting = 'Hello'
text = 'world.'
}
''')
}
protected void tearDown() {
super.tearDown()
service = null
}
void testSayConfig() {
assertEquals 'Hello world.', service.sayConfig()
}
void testSay() {
assertEquals 'Hello mrhaki', service.say('mrhaki')
}
}
Code written with Grails 1.1.2.
Original blog post written on December 01, 2009.
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.
Original blog post written on May 11, 2016.