Grails Tests with Cucumber

Recently one of my customers decided to introduce functional tests. The tests should be run beside the already existing unit and integration tests, utilizing a behaviour-driven development approach (BDD). Behaviour-driven development is an approach to specification based testing, instead of source code based testing. Cucumber enables writing BDD specifications for the Ruby programming language, but there are various implementations for other environments. One of them is Cucumber-JVM, a port of Cucumber for the Java virtual machine.

Cucumber components can be devided into three categories: features, steps and hooks.

Features contain the human-readable specification. A specification consists of a description and various scenarios that need to be successfully executed. A scenario has at least three parts:

Of course, the term “textual description” is not quite true as there needs to be some sort of common agreement about the syntax/semantic of feature files. For writing feature files, Cucumber uses Gherkin, a small programming language with a convenient to read syntax. Let’s have an example:

Feature: log in to admin application
  Administrative functions need to be guarded with a login page

  Scenario: someone opens a protected link
    Given a user opens the browser
    When she opens the "admin/customer/list" link
    Then she will get a login page

The example feature description above shows the definition of a single section. Gherkin would allow multiple scenarios and slightly complex scenario definitions with multiple given/when/then blocks. As can be seen above, the feature is human-readable and definitly not as complex as actual source code.

In my case, the customers application is a Grails application. There is a Cucumber Grails plugin available that we chose to add to our BuildConfig.groovy as additional plugin dependency.

Be aware that Groovy 2.1.x ships with Groovy 1.8.x. The current Cucumber Grails plugin (0.10.0) has a dependency on the Spock Groovy 2.0 build that needs to be excluded manually in BuildConfig.groovy in case you’re running Grails <= 2.1.x.

Once the Grails plugin is added to BuildConfig.groovy, Cucumber specifications can be executed by running test-app. Let’s assume we saved the specification above in a file called AdminLogin.feature. In order to let the Cucumber plugin find the feature specification in the classpath, it needs to be put in the test/functional folder. Afterwards we can tell Grails to run all functional Cucumber tests with the following command:

grails test-app functional:cucumber

Be aware that this restricts test-app to execute only functional Cucumber tests. All functional tests can be executed without the selector via

grails test-app :functional

The result of running test-app looks similar to this:

| Running 1 cucumber test...

1 Scenarios (
1 undefined
)
3 Steps (
3 undefined
)
0m
0.237s

You can implement missing steps with the snippets below:

Given(~'^a user opens the browser$') { ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}
When(~'^she opens the "([^"]*)" link$') { String arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}
Then(~'^she will get a login page$') { ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}
| Completed 1 cucumber test, 1 failed in 605ms
| Tests FAILED

Ups, we wrote a specification but there is an important piece missing: the so-called steps and hooks. Steps are needed to programmatically interact with our application. Cucumber leaves the decision about the tool we use for the steps up to us. As the project is about a web application, we needed some sort of web testing library to implement the steps. We chose to go with Geb, a Groovy library to automate web testing.

The Grails plugin output shown above already gives us a hint on how the step implementations should look like. We can copy these step definition stubs as a basis for our step implementation. The steps are defined in a simple Groovy file, it’s recommended to use a separate package to avoid loading issues by the Cucumber Grails plugin. The file is placed in the test/functional/steps folder (because we are using the steps package in the Groovy file) of the application:

package steps

import pages.admin.LoginPage
import static cucumber.api.groovy.EN.*

Given(~'^a user opens the browser$') {->

}
When(~'^she opens the "([^"]*)" link$') { String link ->
    
}
Then(~'^she will get a login page$') {->
    
}

Given, When and Then are actually static method calls to the Cucumber-JVM Groovy API. Every method is called with two arguments: a regular expression pattern (the bitwise negator is used to generate a java.util.regex.Pattern from the String) and a closure. The closure code comes with as many parameters as the regular expression amount of groups. Because we used double quotes for the link in the feature file we triggered Cucumber to guess this was a valid argument to our closure block. Of course the regular expression can be customized if needed, Cucumber only provides a starting point with the given stub code.

Now it’s time for Geb entering the stage. In order to add a Geb Browser instance to our step code, we need to add a hook to our code. Cucumber hooks are needed to execute code before and after the execution of a scenario. In our case we want the code to be global, as we use Geb in every function Cucumber test case and need to ensure it is setup correctly. We place the Groovy file containing the hooks in the test/functional/support folder, as the Groovy code is using the support package:

package support

import geb.Browser
import geb.binding.BindingUpdater

import static cucumber.api.groovy.Hooks.*

Before () {
    bindingUpdater = new BindingUpdater(binding, new Browser())
    bindingUpdater.initialize()
}

After () {
    bindingUpdater.remove ()
}

The BindingUpdater ensures that every step has access to the Browser instance via a browser variable. In addition, it provides a set of methods that are automatically forwarded to this Browser instance. Examples include, get, at, via and other important methods of the Browser. Let’s see how our steps can finally be implemented by utilizing Geb:

package steps

import static cucumber.api.groovy.EN.*
import pages.admin.LoginPage

Given(~'^a user opens the browser$') {->

}
When(~'^she opens the "([^"]*)" link$') { String secureLink ->
    go secureLink
}
Then(~'^she will get a login page$') {->
    at LoginPage
}

As you can see, instead of writing browser.go link we can simply use go link because the BindingUpdater set up method forwarding for this method. After the given link is opened with go link a Geb page is used to validate whether the login page is now shown in front of the secured page:

package pages.admin

import geb.Page

/**
 * Representation of the admin login page.
 */
class LoginPage extends Page {

    static url = "admin/login"

    static at = {
        (title =~ "Login") as Boolean
    }

    static content = {
        txtLogin    { $("input[name=j_username]") }
        txtPassword { $("input[name=j_password]") }

        btnLogin { $("input.submit_login") }
    }

    def login(String name, String password)  {
        txtLogin = name
        txtPassword = password

        btnLogin.click()
    }
}

Geb uses the at verifier to determine whether the login page is shown or not.

We’re done with our first Cucumber specification!

Update

I created a blank Grails 2.1.5 project and added the example above including an initial Geb and Cucumber configuration that should help getting things up and running.

Conclusion

The Grails Cucumber plugin adds Cucumber-JVM support to Grails applications. Together with Geb, Cucumber can be used to create BDD-style specifications that in turn are executed at run-time using the Groovy web testing library underneath.