gherkin

Gherkin it! Other approach for describing system behavior (with examples)

PART I. What is Gherkin And Why Should I Use It?

If you work in a team where people work collaboratively together, you should know how important communication is. Even agile methodology cannot save you from spending two-week iteration on developing misunderstanding. So how can people improve their work?

Without going far in the history, the main point is that people created TDD (Test-Driven Development) for that purpose. However, there is no silver bullet for solving all problems, and this methodology has its own issues. The issue that will be described in this article is “How can non-technical people (e.g. stakeholders, managers, etc.) productively communicate with developers and testers?” This lack of communication can lead to unclear and incomplete requirements and underestimating of test coverage.

That’s when BDD (Behavior-Driven Development) comes in. It is based on TDD and encourages collaboration between developers, QA and non-technical or business participants in a software project. The main purpose of BDD is to describe system architecture in terms of domain expert, rather than a programmer. This approach speeds up the process of getting feedback and removes the traditional language barriers between the creators of the software and its users.

For describing system behavior there is a Domain Specific Language called Gherkin. It’s easy to use, helps readability for business users and allows for easy automated testing. To read about its syntax you can use this link. Although it’s very helpful for programmers and testers, in this article we won’t consider Gherkin as a scripting language for writing tests. Instead we will use it like communication tool. It’s very useful when it comes to writing project documentation because it is close enough to natural language that both technical and non-technical people can collaborate. At the same time it has enough constraints to encourage thinking in terms of behavior. We can say that it provides a very clear and concise way of explaining a feature, without confusion.

So how exactly Gherkin helps to gather and write requirements? The whole point is in discussion. Language’s flexibility and rules stimulate every participant of the discussion to take active part by asking questions. When discussing the scenarios, participants will ask, for example:

  • What result should be when we change one of the “Given” statements?
  • Is this the only steps to get such result?
  • Is this outcome described always resulting from events in “Given” context?

And there could be a lot of other questions. This can help to uncover further scenarios which clarify the requirements. For instance, a domain expert noticing that there are no rules for non-Premium users to get refunding might reword the corresponding requirement to add appropriate rules. Answers to these questions will save the whole team a lot of time. Programmers will actually get a deeper understanding of the software they’re ought to write. And business participants can change requirements immediate, if they find out that some features, for example, could not be implemented.

And still you can think “Why do I have to use Gherkin? We can make discussion and ask questions without using some special languages.” The answer is “You don’t. If it doesn’t fit your needs, do not use it.” Everything depends on your organization’s approach. Gherkin is perfect for writing requirements because it encourages you to ask right questions. Firstly, every feature in this method is described in separate .feature file. So you will not be confused and can concentrate on specific function. Secondly, due to Gherkin’s rules and constraints, every requirement is documented in the same manner. It helps people to communicate in the same language with the same terminology. Thirdly, the “Given-When-Then” structure causes more specific questions, because requirement is more detailed. The other advantage is that you can transform scenarios into automated tests. You can do this using Cucumber or other tools that understand Gherkin. Let’s look at the example.

feature

Example of simple .feature file

This picture above shows a well described requirement of one feature. Nevertheless it causes questions, like “What is the expected behavior if there is no items to make replacement?” Answer to this question will show the programmer what he should implement, without trying to guess the expected behavior.

So the choice is yours. Using Gherkin gives you some benefits in your work, but it definitely can’t solve all your problems. If you feel that there are a lot of problems in communication between team members, and this leads to delays and bad quality of software – you should try this approach.

PART II. Using Cucumber-JVM And Parallel Testing

Project Description And Creating Feature file

Now let’s practice a little bit. We’ll try to create a test framework using Cucumber-JVM with the help of WebDriver for running acceptance tests of web applications. If the team uses Continuous Integration, conducting acceptance tests might be useful for testing the app after unit or integration tests.

You’ll need:

  • To download the project;
  • Maven for launching tests;
  • Mozilla Firefox installed.

We’ll use parallel testing. After downloading the project you need to open Cucumber-JVM-Parallel folder and run the following command: mvn clean install.

It will launch the project and the tests – two browsers will open. Each browser corresponds to its Cucumber feature file. After completion, you can view the report in the directory /target/cucumber-report/index.html.

Also, you can use the Run As -> Maven install. And this is how the result looks like:

jvm-1

Now let’s talk about details and project structure. If you don’t have enough knowledge about Cucumber-JVM you can look through its readme instructions.

Feature files

These are the first file that you need. Feature file describes the steps or behavior that you want to automate. In our example, we have two separate files. They use Cucumber tags, which can be applied to all scenarios or to certain test.
jvm-2

On the above image you can see the code of two feature files. They are located in “src/test/resources” directory. Each file has certain tag (@autocorrect and @search) and defines certain scenario.

Glue Code and Page Object

Glue Code

After we have created a couple of scenarios it is necessary to write a glue code for each step.
Each step corresponds to certain method which is marked with some annotations. See “src/java/cucumber.jvm.parallel/cucumber/stepdefs”.

public class SearchStepDefs {
    private SearchPageObject searchPage;
    private WebDriver webDriver;
 
    public SearchStepDefs(SharedDriver webDriver) {
        this.webDriver = webDriver;
        searchPage = new SearchPageObject(webDriver);
    }
 
    @Given("^I am on the website '(.+)'$")
    public void I_am_on_the_website(String url) throws Throwable {
        webDriver.get(url);
    }
 
    @When("^I submit the search term '(.+)'$")
    public void I_submit_the_search_term(String searchTerm) throws Throwable {
        searchPage.enterSearchTerm(searchTerm);
        searchPage.submitSearch();
    }
 
    @When("^accept the first search result$")
    public void accept_the_first_search_result() throws Throwable {
        searchPage.acceptSearchResult(0);
 
        //wait up to 5 seconds for redirect to complete
        for(int i=0; i<5; i++) {
            if(!webDriver.getCurrentUrl().contains("google")) { break; }
            Thread.sleep(1000);
        }
    }
 
    @Then("^I should be on the page '(.+)'$")
    public void I_should_be_on_the_page(String url) throws Throwable {
        assertEquals(url, webDriver.getCurrentUrl());
    }

You may notice that I use ShareDriver object for communication with browser. It is based on one of the examples of dividing one browser session between all the tests. This eliminates the need to run WebDriver object for each test, which affects the speed of execution. In this way we create one session per thread. ShareDriver class is located in “/src/test/java/cucumber.jvm.parallel/cucumber”.

Page Objects

The code below shows how to create “SearchPageObject” class which represents Google search page and all of its elements – “/src/test/java/cucumber.jvm.parallel/pageobjects”. While it is not a necessary thing, there is still a good practice of using Page Object pattern for easy support of large projects.

package cucumber.jvm.parallel.pageobjects;
 
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
 
import java.util.List;
 
public class SearchPageObject {
    private static WebDriver webDriver;
 
    public SearchPageObject(WebDriver webDriver) {
        this.webDriver = webDriver;
    }
 
    private By searchTermField = By.id("gbqfq");
    private By submitSearch = By.id("gbqfb");
    private By searchResults = By.id("search");
 
    public void enterSearchTerm(String searchTerm) {
        webDriver.findElement(searchTermField).sendKeys(searchTerm);
    }
 
    public void submitSearch() {
        webDriver.findElement(submitSearch).click();
    }
 
    public void acceptSearchResult(int id) {
        List<WebElement> searchResultList = webDriver.findElement(searchResults).findElements(By.tagName("li"));
 
        searchResultList.get(id).findElements(By.tagName("a")).get(0).click();
    }
}

In the code above you see defining of three controls of the page and actions performed with the page.

Creating runners and reports

Creating runners for tests

The next step would be creating runners for our autotests. For these purposes we’ll use Junit.

package cucumber.jvm.parallel.cucumber;
 
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
 
@RunWith(Cucumber.class)
@Cucumber.Options(features = "target/test-classes/cucumber/examples/", tags = {"@search"}, format = {"html:target/cucumber-report/search"})
public class SearchAT {
}

In the above code you can see specifying feature fine in “SearchAT.class” file. We also define (@search) tag, which refers to the above mentioned tag in cucumber feature file, and shows the path to html report. In other words, these notifications are to define the command “run all tests with @search tag and write the result to the directory /search directory”.

Also we have another class – “AutoCorrectAT”, which does the same for all tests with “autocorrect” tag. Both of these classes can be found in “/src/test/java/cucumber.jvm.parallel/cucumber”. For creating another thread you just need to add another runner class with another tag.

Parallel tests running

For parallel running of Cucumber-JVM tests using WebDriver to interact with the browser, switch to Maven POM file and view settings:
runners

You can see maven-surefire-plugin used for launching our acceptance tests, and any class which ends with *AT will be run as Junit test class. The forkCount variable is specified in its settings and is set to value 5. This means that we can run up to 5 threads (5 running classes) at one time.
runners-2

Reports

The result of running two feature files would be reports located in two different directories. To simplify reporting, our final step is to combine these two reports into a single report. We’ll use “/src/main/java/cucumber.jvm.parallel/ReportMerger” code. It is executed with exec-maven-plugin in Maven POM file.

The result of its work would be index.html file in root directory, which consists of several subreports.

About Max

Despite my considerably young age I can already be considered an experienced QA automation engineer and I have already been trusted with a team of talented experts under my lead. My hobby is football and music.


no comments yet

Be the first to comment this post!

Would you like to share your thoughts?

Images are for demo purposes only and are properties of their respective owners.
Old Paper by ThunderThemes.net © 2017

×