-
Notifications
You must be signed in to change notification settings - Fork 35
Plugin Guide
- Introduction
- Plugin Installation
.feature
Files Location- Step Implementations Location
- Compiled Steps
- Step Implementations
- Before & After Code
- Running Cucumber Features
- Plugin Configuration
- FAQ & Pitfalls
grails-cucumber is a Grails plugin for Cucumber based on Cucumber-JVM. Cucumber-JVM is the JVM implementation of cucumber and it supports many JVM languages. Groovy is one of them.
grails-cucumber is a functional test plugin for grails. It is not meant to implement tests on the unit test level. It is only available in the functional test phase.
The plugin runs cucumber inside a running grails application which allows us to use the grails api in the cucumber step implementations. We can call GORM stuff like dynamic finders, services or even controllers.
since 0.10.0, Grails 2.3
Note Running functional tests and the app in the same process is deprecated by Grails. It (currently) does still work but it is not recommended to avoid subtle differences between test and live environment. Therefore the in-process features of the plugin are deprecated too.
grails-cucumber is a normal grails plugin. To use it in your grails application just add it to the plugins
configuration block in BuildConfig.groovy
like this (using the latest available version of the plugin):
plugins {
test ":cucumber:0.7.0"
}
The only convention regarding cucumber .feature
files is that they should be in the test/functional
directory. Inside it you can use any layout you like to structure the features.
The plugin will tell Cucumber-JVM to look for features in this directory and Cucumber-JVM will scan it recursivly.
If you need to you can override this path. See Plugin Configuration.
The step implementations follow the same convention as the .feature
s. They should be in test/functional
and inside it you can use any layout you like to structure the steps.
The plugin will tell Cucumber-JVM to look for the steps in this directory and Cucumber-JVM will scan it recursivly.
Note that you should not mix cucumber groovy scripts with other groovy scripts. Cucumber-JVM will run all groovy scripts it will find in the given path. Chances are high that this will fail and is probably not what you want anyway.
If you need to you can override this path. See Plugin Configuration.
since 0.9.0
It is possible to compile the step files before running the features. There are two things to configure in CucumberConfig.groovy
(see configuration): first, the location of the source files using the sources
option and second, the classpath of the steps using the glue
option:
cucumber {
// steps, hooks etc that will be compiled
sources = ["test/cucumber"]
// .. and where cucumber will find the compiled steps & hooks
glue = ["classpath:<the steps and hooks package>"]
}
A layout that seperates the feature files from the step code could look like this:
cucumber {
// here we save the feature files...
features = ["test/cucumber"]
// steps, hooks etc that will be compiled
// if the steps are in "test/functional" we do not need to configure it
// sources = ["test/functional"]
// .. and where cucumber will find the compiled steps & hooks
glue = ["classpath:<the steps and hooks package>"]
}
The steps should be in their own package and there should be no other (normal) classes in this package. Cucumber will load all classes in the given package(s). To avoid complications it is recommended to keep the steps in isolation. It is ok to put (normal) classes into the sources
directories to compile them but they should be in a different package that is not listed in the glue
configuration.
See Plugin Configuration for the details of the source
and glue
option.
This section does contain some basic information for implementing steps: What is possible at all and how do I use specific grails functionality.
deprecated since 0.10.0
Grails 2.3+ Note: this will not work in forked mode but only in non forked mode.
There is nothing special about using GORM, just use it as in production code. Having a simple domain class Book
package books
class Book {
String author
String title
}
we can call dynamic finders as usual:
When (~"^I add \"([^\"]*)\"\$") { String bookTitle ->
def book = Book.findByTitle (bookTitle)
...
}
deprecated since 0.10.0
Grails 2.3+ Note: this will not work in forked mode but only in non forked mode.
To create a Service in a cucumber step call appCtx.getBean ("<bean name>")
like this:
Given (~"^I have already added \"([^\"]*)\"\$") { String bookTitle ->
def bookService = appCtx.getBean ("bookService")
// do something with your service
}
deprecated since 0.10.0
Grails 2.3+ Note: this will not work in forked mode but only in non forked mode.
We can create & use Controllers in the same way as in a normal grails controller integration test. We just have to add some setup & cleanup that we get automatically when we implement normal integration tests by extending GroovyTestCase
. That is, setting up the mock request , response and session objects.
It is just a few lines you have to call from from the cucumber Before
and After
hooks.
since 0. 6.0
Alternatively to adding the two hooks manually we can also add a simple configuration block into a support file (like env.groovy
) which will create the two hooks.
import static grails.plugin.cucumber.Hooks.hooks
hooks {
request ("@req")
}
The request
setting takes a cucumber tag expression as parameter and adds a Before
& After
hook passing the tag expression ("@req"
in the above example) to the hooks (so they will run only for features or scenarios marked with the @req
tag).
The next section shows the code that is executed in the request hooks. See also Standard Hooks in Options.
Here is the required code to put in the Before
and After
hooks to get controller support in the step implementations:
import org.codehaus.groovy.grails.test.support.GrailsTestRequestEnvironmentInterceptor
this.metaClass.mixin (cucumber.runtime.groovy.Hooks)
GrailsTestRequestEnvironmentInterceptor scenarioInterceptor
Before () {
scenarioInterceptor = new GrailsTestRequestEnvironmentInterceptor (appCtx)
scenarioInterceptor.init ()
}
After () {
scenarioInterceptor.destroy ()
}
See Testing-Grails-with-Cucumber-and-Geb for a complete tutorial.
Apart from a single constellation the plugin does/can not provide any support to wrap a scenario into a transaction to automate the cleanup of the database. We will have to provide Before
and After
hooks to setup and cleanup the database (see cucumber & Grails: Transaction Rollback). There are two options:
- re-create the database schema on each scenario
- restore the original database state with update/delete statements
The plugin integrates cucumber as a grails test type into the grails test infrastructure. You can run the cucumber features via the grails test-app
command and the test results will be included in the normal grails test reports.
Currently the plugin registers the cucumber test type only to the functional test phase. To run the cucumber features you call grails by one of the following commands:
grails test-app functional:cucumber
grails test-app :cucumber
Or, if you do not use a second functional test plugin you can also use:
grails test-app functional:
since 0.6.0
If the command line contains :cucumber
, @tag
arguments are evaluated to filter execution of features or scenarios. Standard cucumber syntax applies without the --tags
option keyword. Setting tags on the comand line will overwrite CucumberConfig.groovy
:
grails test-app :cucumber @foo,~@bar @zap
since 0.8.0
If the command line contains :cucumber
and some other arguments (i.e no @tag
s) they are evaluated as file/dir and line filter for features and scenarios. The filter info is just passed through to cucumber and can be whatever cucumber does except. Here are a few examples:
// features
grails test-app :cucumber foo.feature bar.feature
// feature with line numbers
grails test-app :cucumber foo.feature:10:17
// feature with "full" path
grails test-app :cucumber test/functional/foo/bar.feature
// feature directories
grails test-app :cucumber foodir bardir
Normally you would have to provide the full path (relative to the grails project root directory) to the files/dirs. As a convinience, the given feature files/dirs will be prefixed with the configured feature path (see Options).
If the feature path is not changed, all files/dirs will be prefixed with test/functional
. Calling
grails test-app :cucumber foo.feature
the plugin will pass test/functional/foo.feature
to cucumber.
Note that this step is skipped if you have configured multiple feature paths. Because the plugin can not decide which feature path contains a given file/dir you have to provide the full path yourself.
since 1.1.0, this option has been renamed (cucumber-jvm 1.2.0), its old name will still work
(since 0.10.0)
Using the --plugin
arg on the command line will add an additional plugin. The plugin description will be passed "as is" to cucumber and has the same syntax as cucumbers --plugin
option:
// use json plugin
grails test-app :cucumber --plugin=json:target/test-reports/cucumber.json
Note that there is a '=' character between --plugin
and its value and that only one --plugin
option can be used. Multiple plugins can be configured in CucumberConfig.groovy
(see Options).
In JUnit we have test suites and tests. In Cucumber we have features, scenarios and steps. The plugin maps features to test suites and scenarios to tests. There is no direct mapping for steps. The steps will be reported as part of their scenario.
Grails does only distinguish between failures and errors and knows nothing about undefined steps. Undefined steps will be therefore reported as failure which makes the scenario fail too.
The plugin integrates into grails test reporting. The normal cucumber output can be found in the html or plain test reports in target/test-reports
.
The plugin does use a couple of default settings that can be overriden by CucumberConfig.groovy
if you need to. If a setting is not given in the configuration file the default will be used.
The defaults in CucumberConfig.groovy
notation are:
cucumber {
tags = []
features = ["test/functional"]
glue = ["test/functional"]
}
The hardcoded test/cucumber
path used in the plugin before version 0.4.0 is now deprecated. If you still like to use it you can add it to the features
and steps
setting in CucumberConfig.groovy
.
cucumber {
features = ["test/cucumber"]
glue = ["test/cucumber"]
}
The plugin will read the configuration from grails-app/conf/CucumberConfig.groovy
. It is a a standard config slurper file.
We can adjust the paths where cucumber will look for
.feature
files and step implementations so putting the configuration along the cucumer files does not work.
Cucumber tags can be set using the tags
configuration option:
cucumber {
tags = ["@implemented", "~@ignored"]
}
tags
is a list of strings where each item corresponds to a single cucumber --tags
option. See the cucumber documentation to read more about the --tags
switch.
To override or extend the locations where cucumber will search for .feature
files you can use the features
option:
cucumber {
features = [
"test/functional/features",
"test/functional/featuresOfCurrentSprint"
]
}
features
is a list of paths where each path is relative (below) the grails application root directory.
Note that settings this option will override the default
test/functional
path. If you want to keep it you have to add it to thefeatures
path list.
since 1.1.0, this option has been renamed (cucumber-jvm 1.2.0), its old name will still work
(since 0.10.0)
Additional cucumber formats/formatters can be set with the plugins
configuration option:
cucumber {
plugins = [
"json:target/test-reports/cucumber.json",
"html:target/test-reports/cucumber"
]
}
plugins
is a list of strings where each item corresponds to a single cucumber --plugin
option.
The plugins (default) grails formatter will aways run.
since 0.9.0
To compile the steps before running the features you have to configure the location of the step source files. This is done with the source
option:
cucumber {
// steps, hooks etc that will be compiled
sources = ["test/cucumber"]
// remember to set the glue option!
}
It is possible to list multiple source directories.
If grails-cucumber does find a sources
option in the configuration it will compile all files in the given directories. sources
does not have a default value, so if not set the plugin will not use compiled steps.
If you use test/functional
as the step source directory you don't have to add the source
option. test/functional
will be compiled by grails automatically.
To use compiled steps it it also required to configure the packages of the steps in the glue
option. This is described in the next section.
To override or extend the locations cucumber will search for groovy scripts with gherkin steps or hooks you can use the glue
option:
cucumber {
glue = [
"test/functional/steps",
"test/functional/hooks"
]
}
glue
is a list of paths where each path is relative (below) the grails application root directory.
Note that settings this option will override the default
test/functional
path. If you want to keep it you have to add it to theglue
path list.
since 0.9.0
If the steps and hooks are compiled we have to tell cucumber the package names instead of the paths to the step source files. This is done using the classpath
notation:
cucumber {
glue = [
"classpath:<package name>",
"classpath:<another package name>"
]
}
since 0.6.0, deprecated since 0.10.0
Grails 2.3+ Note: this will not work in forked mode but only in non forked mode.
The plugin provides a couple of standard hooks that can be enabled using the hooks
configuration block. It should be placed in a groovy file on the glue
path:
import static grails.plugin.cucumber.Hooks.hooks
hooks {
integration ("@i9n")
}
The integration
setting enables grails integration test support which we will get automatically in normal integration tests by extending GroovyTestCase
. It will simply create a Before
and a After
hook pair with the given tag expression to set up and clean up grails integration testing. Note that this is only usefull for ui-less testing.
The following hooks are supported:
-
request
: enable mock request, response and session (see integration testing) -
transaction
: enable automatic rollback (works only in integration test mode, see integration testing) -
integration
: combination ofrequest
andtransaction
(see integration testing)
-
The plugin fails when I try to run features in a non-english language.
If cucumber does not recognize the
# language: <language code>
comment at the beginning of a feature file it is probably because of a byte order marker (BOM). Remove it and try again.