Gauge – a lightweight behavior-driven testing tool

In this article, I am going to report on the test framework Gauge from the ThoughtWorks corporation. This is a tool which I met for the first time when I was writing automated end-to-end tests (E2E) for various web applications within a web platform. The purpose of the tests is to progressively check whether certain functions such as single sign-out, appropriate redirection to other pages or access authorisations to certain elements of a selected web application function as they should.

The Selenium WebDriver from ThoughtWorks is suited to execute automated E2E tests using the browser. This automatically simulates the user entries in a selected web browser such as Firefox, Chrome or InternetExplorer. The API from Selenium WebDriver can be used in various languages such as Java, C#, Python and is easy to integrate into custom Maven projects.

Selenium does not, however, provide a framework to structure the individual tests. An important pre-requisite for me when selecting an appropriate framework was that the tests would be easy to understand as regards their implementation for team members without a technical background. Furthermore, there are several alternatives which allow software developers to write their tests in Business Language. This means that the tests can also be used for documentation. Cucumber, for example, describes its tests in simple text and supports use in common languages such as Java, JavaScript, C++ and .NET. Throughout, it focuses on the description of the behavior of the software and presupposes certain syntax elements such as Given, When and Then for the test description. The framework JBehave works in a similar fashion and uses some of the same syntax as Cucumber. These frameworks did not, however, satisfy all my requirements. I wanted to write tests in Business Language without having to force myself into the stringent syntax corset of Cucumber and JBehave. Then I ran into Gauge via Selenium.

What is Gauge?

The open source test framework Gauge consists of a very simple syntax. Gauge’s modular architecture can be expanded in the form of plugins. It expects test specifications in human readable, self-explanatory markdown. The specifications here are divided into scenarios and then these are divided into steps. The individual elements are described in more detail below in the form of an elaborate example. A gauge specification has the following basic structure:

End-to-End-Tests
=============

Go to Gauge Documentation Page
--------

* Go to Gauge main Page
* Click on Gauge Documentation Page button

The steps are subsequently mapped to functions and/or methods – and it is these functions and methods which implement the actual test logic. In Java, for example, a step implementation would appear as follows:

@Step("Go to Gauge main Page")
public void goToGaugeMain(){
  ...
}

@Step("Click on Gauge Documentation Page button")
public void clickOnDocuBtn(){
  ...
}

Gauge also has the following characteristics. It can be used without a great deal of familiarisation and can be installed and initialised with a command. Moreover, it is not bound to any certain IDE or to a platform. Gauge tests can be implemented in C#, Java, JavaScript, Python and Ruby as standard. It is supported by IDEs such as IntelliJ, Eclipse and Visual Studio. Gauge can be integrated into the build tools Maven and Gradle and it includes the two report plugins HTML report and XML report. Large quantities of test data can be read from text files, CSV and additional formats keeping the specifications readable..

Getting Started with Gauge

After I downloaded and installed Gauge, I was able to generate the basic framework for my project by executing the simple command ‘$ gauge –init java_maven_selenium’. Here I used the Java Maven Selenium template, which allows test implementations in Java code, uses Maven as a build tool and provides Selenium as a WebDriver. With this command, all required dependencies are defined in the pom.xml. ‘$ mvn test’ uses the previously integrated JUnit runner to launch an example included in the standard installation. Existing Gauge templates for projects are displayed with the console command ‘$ gauge –list-templates’.

The folder structure in Gauge subsequently appears as follows. I intentionally left out Maven-specific and Selenium-specific files and folders here.

|-- env
     '-- default
          '-- default.properties
|-- manifest.json
|-- specs
     '-- example.spec
|-- src
     '-- test
          '-- java
               '-- StepImplementation.java      

The /env/default folder contains environment variables which can be used during execution. The specifications are in the specs folder. The manifest.json configures the implementation language and the plugins used for Gauge. In my Java Maven Selenium project, the implementation language is Java and it also includes the plugin html report, a plugin for generating a report in HTML which illustrates all the results of the tests graphically.

I added the file /env/default/browser.properties with the contents ‘BROWSER = CHROME’ in order to use Chrome as my preferred browser for Selenium. Gauge inputs the defined properties as system variables during execution. The variable used is the one in the class DriverFactory and which is used when Selenium and JUnit are initialised.

public class DriverFactory {

    public static WebDriver getDriver() {
        // Gauge reads set environment variable from browser.properties
        String browser = System.getenv("BROWSER");
        if (browser == null) {
            return new FirefoxDriver();
        }
        switch (browser)
        {
            case "IE":
                return new InternetExplorerDriver();
            case "CHROME":
                return new ChromeDriver();
            default:
                return new FirefoxDriver();
        }
    }
}

The most relevant specifications for programming custom tests are those inside the specs folder. These specifications specify the order the test will be conducted in and aggregate individual test steps, called steps in Gauge, into blocks – the so-called scenarios.

To illustrate this, I have added a scenario and three steps to the example.spec in my project.

Getting Started with Gauge
==========================

* Navigate to "http://getgauge.io"

Get Started
-----------
* Go to Gauge Get Started Page

Go to Documentation Page
------------------------
* Go to Gauge Documentation
* Go to Step Alias Page
* Is Page title "Step alias · Gauge Documentation"?

The name of each specification is designated with the placement of ==== under its name. Another option would be to add # in front of the specification name. In my example, the specification is called Getting Started with Gauge. A specification contains at least one scenario. Scenarios are designated with — below their names or ## in front of them. Get Started and Go to Documentation Page are the two scenarios within my specification. Then come the steps that are marked with an asterisk. The symbols ‘ “, <, > ’ are reserved for parameters here. The step ‘* Navigate to “http://getgauge.io”’, for example, includes the parameter ‘http://getgauge.io’. This is transferred to the step implementation during execution. A special feature are the so-called context steps and teardown steps. While context steps are executed before every execution of a scenario, teardown steps are executed after every scenario. In Gauge, context steps are defined by executing a step before starting up the first scenario. ‘* Navigate to “http://getgauge.io”’ is an example of a context step. In contrast, a step is a teardown step when at least three underlines in a row were written.

____________________
This is a teardown step

* Logout user "stan"

The Java-implementation of this specification is located at /src/test/java and it looks like this:

package de.triology.blog.gauge_e2e_tests;

import com.thoughtworks.gauge.Gauge;
import com.thoughtworks.gauge.Step;
import driver.Driver;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import static org.junit.Assert.assertTrue;

public class StepImplementation {

    @Step("Navigate to <url>")
    public void navigateTo(String url) {
        Driver.webDriver.get(url);
        assertTrue(Driver.webDriver.getTitle().contains("Gauge"));
    }

    @Step("Go to Gauge Get Started Page")
    public void gotoGetStartedPage() throws InterruptedException {
        WebElement getStartedButton = Driver.webDriver.findElement(By.xpath("//*[@id=\"content\"]/div[1]/section[1]/div[2]/a[1]"));
        getStartedButton.click();
        String title = Driver.webDriver.getTitle();
        Gauge.writeMessage("Page title is " + title);
        assertThat(title, is("Gauge | ThoughtWorks"));
    }

    @Step("Go to Gauge Documentation")
    public void gotoDocumentationPage() throws InterruptedException {
        Driver.webDriver.get("http://getgauge.io/documentation/user/current/");
        String title = Driver.webDriver.getTitle();
        Gauge.writeMessage("Page title is " + title);
        assertThat(title, is("Introduction · Gauge Documentation"));

    }

    @Step("Go to Step Alias Page")
    public void gotoStepAliasPage() throws InterruptedException {
        Driver.webDriver.get("http://getgauge.io/documentation/user/current/advanced_readings/step_alias.html");
        String title = Driver.webDriver.getTitle();
        Gauge.writeMessage("Page title is " + title);
        assertThat(title, is("Step alias · Gauge Documentation"));
    }

    @Step("Is Page title <title>?")
    public void checkPageTitle(String title) {
        String actualTitle = Driver.webDriver.getTitle();
        assertThat(actualTitle,is(title));
        Gauge.writeMessage("Page title is " + actualTitle);
        Gauge.writeMessage("Page title should be " + title);
    }
}

The order of the implementation does not matter. Gauge automatically searches for methods with the corresponding ‘@Step’ annotation in any Java files which are in the src/test/java folder. The order the scenarios and steps are in within the Gauge specification and the order the implementation is in should coincide with one another for the purpose of legibility. In the Java implementation of the first step executed by the method ‘public void navigateTo(String url)’, the set URL ‘http://getgauge.io’ from example.spec is transferred as a string. Then the WebDriver jumps to the appropriate URL and checks whether the title of the DOM contains the corresponding page “Gauge”. In the implementation of the step Go to Gauge Get Started Page which is found in the first scenario, a button element is clicked automatically on the page http://getgauge.io and the title of the next page is noted in the Gauge report. The next step which is executed before the second scenario is the context stepGo to Gauge Get Started Page again. Subsequently, the documentation page is navigated to and then to a subpage. Finally, a check is performed to verify whether the title of the current page corresponds to the specified title ‘Step alias · Gauge Documentation’ from the spec-file.

This illustration portrays the test output in the console of the IDE NetBeans in the Maven project. As can be seen, all tests have been completed successfully and an HTML with all the specific information about this test run has been generated in the reports folder by the Gauge plugin html report. Every green tick here stands for a successfully completed step.

Conclusion

What I found particularly easy about Gauge was getting started. After downloading Gauge, a language plugin for Java can be installed using ‘$ gauge –install java’ and then initialised directly into the appropriate project with the command ‘$ gauge –init java’. The subsequently created Gauge project has a simple, straightforward structure. The specifications written in markdown are intuitive and the designations of the individual structural elements (specification, scenario, step) are self-explanatory when used correctly so that they, as mentioned above, can be used for the purpose of documentation or for correspondence with colleagues who are out of the loop. Because of the step syntax, writing integration tests or E2E tests is rather easy with Gauge. Both of the report plugins which are currently available, HTML report and XML report, generate HTML reports and XML reports, respectively, for the test execution so that these can be shared or published across platforms.

As already mentioned, Gauge already supports some languages and IDEs. Moreover, ThoughtWorks offers a [plugin API](http://getgauge.io/documentation/technical/current/api.html). It is therefore to be expected that additional languages and IDEs will be supported by Gauge in future.

As a closing statement, for my part, I can only recommend that every developer who finds the current support for language and IDEs appealing tries out Gauge for themselves. Getting started is simple and straightforward and Gauge provides a variety of helpful functions. Examples of some of these are context steps and teardown steps, providing specifications and scenarios with tags, inputting data from text files and CSV files and parameter transfer to implementation functions from tables. Especially in the context of behavior-driven development, a technology with which the tasks, objectives and results of a software are recorded and later executed as automatic tests, it is a test framework worth considering.

Examples of code

Every example of code depicted here can be viewed at Github by clicking on this https://github.com/triologygmbh/gauge-e2e-tests and cloned for the purposes of running your own experiments.

Sources:
* Gauge Dokumentation
* Gauge Plugins
* Gauge Plugin API
* E2E-Test-Beispiel
* Behavior Driven Development
* Blogartikel zu Gauge

Share this article

Malte Kreutzfeldt
Software Development
Always with open eyes for new open source tools, frameworks and best practice development methods, he is allowing his IT horizons to expand with virtually no limits.