Chapter Contents

13 Testing

Geb provides first class support for functional web testing via integration with popular testing frameworks such as Spock, JUnit, TestNG and Cucumber.

13.1 Spock, JUnit & TestNG

The Spock, JUnit and TestNG integrations work fundamentally the same way. They provide subclasses that setup a browser instance that all method calls and property accesses/references resolve against via Groovy’s methodMissing and propertyMissing mechanism.

Recall that the browser instance also forwards any method calls or property accesses/references that it can’t handle to its current page object, which helps to remove a lot of noise from the test.

Consider the following Spock spec…

import geb.spock.GebSpec

class FunctionalSpec extends GebSpec {
    def "go to login"() {
        go "/login"

        title == "Login Screen"

Which is equivalent to…

import geb.spock.GebSpec

class FunctionalSpec extends GebSpec {
    def "go to login"() {
        browser.go "/login"

        then: == "Login Screen"

13.1.1 Configuration

The browser instance is created by the testing integration. The configuration mechanism allows you to control aspects such as the driver implementation and base URL.

13.1.2 Reporting

The Spock, JUnit and TestNG integrations also ship a superclass (the name of the class for each integration module is provided below) that automatically takes reports at the end of test methods with the label “end”. They also set the report group to the name of the test class (substituting “.” for “/”).

The report(String label) browser method is replaced with a specialised version. This method works the same as the browser method, but adds counters and the current test method name as prefixes to the given label.

package my.tests

import geb.spock.GebReportingSpec

class FunctionalSpec extends GebReporting {

    def "login"() {
        go "login"
        username = "me"
        report "login screen" // take a report of the login screen

        title == "Logged in!"

Assuming a configured reportsDir of reports/geb and the default reporters (i.e. ScreenshotReporter and PageSourceReporter), we would find the following files:

The report file name format is:

«test method number»-«report number in test method»-«test method name»-«label».«extension»

Reporting is an extremely useful feature and can help you diagnose test failures much easier. Wherever possible, favour the use of the auto-reporting base classes.

13.1.3 Cookie management

The Spock, JUnit and TestNG integrations will automatically clear the browser’s cookies at the end of each test method. For JUnit 3 this happens in the tearDown() method in geb.junit3.GebTest, for JUnit 4 it happens in an @After method in geb.junit4.GebTest and for TestNG it happens in an @AfterMethod method in geb.testng.GebTest.

The geb.spock.GebSpec class will clear the cookies in the cleanup() method unless the spec is @Stepwise, in which case they are cleared in cleanupSpec() (meaning that all feature methods in a stepwise spec share the same browser state).

This auto-clearing of cookies can be disabled via configuration.

13.1.4 JAR and class names

The following table illustrates the specific JARs and class names for Spock and JUnit.

Framework JAR Base Class Reporting Base Class
Spock geb-spock geb.spock.GebSpec geb.spock.GebReportingSpec
JUnit 4 geb-junit4 geb.junit4.GebTest geb.junit4.GebReportingTest
JUnit 3 geb-junit3 geb.junit3.GebTest geb.junit3.GebReportingTest
TestNG geb-testng geb.testng.GebTest geb.testng.GebReportingTest

13.1.5 Example Projects

The following projects can be used as starting references:

13.1.6 Configuration

Configuration is done in the given block of a scenario or story. Here you can optionally set 3 properties; driver, baseUrl and browser.

You can set the driver property to the driver instance that you want to implicitly created browser instance to use. However, using the configuration mechanism for driver implementation is preferred.

You can set the baseUrl property to the base URL that you want to implicitly created browser instance to use. However, using the configuration mechanism for base url is preferred.

For fine-grained control, you can create your own browser instance and assign it to the browser property. Otherwise, an implicit browser object is created using driver and/or baseUrl if they were explicitly set (otherwise the configuration mechanism is used.)

13.2 Cucumber (Cucumber-JVM)

It is possible to both:

13.2.1 Writing your own steps

Use Geb’s binding management features to bind a browser in before / after hooks, often in a file named env.groovy:

def bindingUpdater
Before() { scenario ->
    bindingUpdater = new BindingUpdater(binding, new Browser())

After() { scenario ->

Then normal Geb commands and objects are available in your Cucumber steps:

import static cucumber.api.groovy.EN.*

Given(~/I am on the DuckDuckGo search page/) { ->
    to DuckDuckGoHomePage
    waitFor { at(DuckDuckGoHomePage) }

When(~/I search for "(.*)"/) { String query ->

Then(~/I can see some results/) { ->
    assert at(DuckDuckGoResultsPage)

Then(~/the first link should be "(.*)"/) { String text ->
    waitFor { page.results }
    assert page.resultLink(0).text()?.contains(text)

13.2.2 Using pre-built steps

The geb-cucumber project has a set of pre-built cucumber steps that drive Geb. So for example a feature with steps similar to the above would look like:

When I go to the duck duck go home page
And I enter "cucumber-jvm github" into the search field
And I click the search button
Then the results table 1st row link matches /cucumber\/cucumber-jvm · GitHub.*/

See geb-cucumber for more examples.

geb-cucumber also does Geb binding automatically, so if it is picked up you don’t need to do it yourself as above.

13.2.3 Example Project

The following project has examples of both writing your own steps and using geb-cucumber:

The Book of Geb - 0.10.0 - October, 2014
Licensed under the Apache License, Version 2.0