Building Selenium framework in java (part III) - how do you fit Cucumber in there

In this article let me explain how I think Cucumber fits Selenium based test framework written in java

|

Introduction

Honestly, until recently, I thought that Cucumber is meant for less experienced test developers, who need some kind of already existing test framework skeleton to be filled in with tests. I couldn’t understand how experienced test architect, who absolutely know how to build whole product test solution from scratch, could benefit from such tool. Today I think it is quite opposite - let me explain how I think Cucumber fits Selenium based test framework written in java.

Cucumber, BDD and project documentation

Cucumber is designed to support Behavior Driven Development process. In BDD methodology, new product features are developed based on previously created scenarios, which are automatically run, even before given feature works. Those scenarios act as acceptance tests, so when development is done and scenario passes, then the work is finished. This is how it works in theory and cucumber supposed to be used. In practice, at least from my experience, Cucumber is forced into the projects by management for one single reason – human readable scenarios (Gherkin), which can act as test cases and project documentation at once. Of course, development process usually stays untouched, because it is too complex to change and understand – this is why gherkin is needed for them in the first place.

This is the point when test architect becomes really angry. He probably already created a test framework, which actually works, has layers (like onion) and everything. The only part missing is gherkin scenarios. So he starts to dig deeper and finds out that introducing Cucumber will break his framework into billion small pieces in flat structure (step definitions), which even cannot inherit from each other. At first it looks like Cucumber is going to seriously limit framework architecture. But it doesn’t have to be that way.

Three layered test framework architecture and Cucumber

To support gherkin, Cucumber introduces step definitions, which map each scenario line into a java method. Classes with such methods cannot extend other step definitions classes. This might bring some discomfort at first, but let’s take a look at the architecture we created in previous part of this blog series:

On test layer level we replace tests and assertions with Cucumber scenarios. Page objects are going to stay as they were in business layer, but what about scenarios? It looks like they have similar purpose as Cucumber step definition methods – they were used to encapsulate some portions of product business logic into one reusable, meaningful method call – just like step definition method. The only difference is that step definition method is called from Cucumber feature file, instead of java test method.

So, taking sample scenario class used to replace login logic:

@AllArgsConstructor
public class LoginScenario implements Scenario<LoginPage, DashboardPage> {
    private BaseUser user;

    @Override
    public DashboardPage run(LoginPage loginPage) {
        return loginPage
            .setEmail(user.getEmail())
            .setPassword(user.getPassword())
            .clickLogin();
    }
}

can be refactored into step definition as follows:

When("^User logs in to the system$", (List<User> users) -> loginPage
        .setEmail(users.get(0).getEmail())
        .setPassword(users.get(0).getPassword())
        .clickLogin());

All practices, rules and standards defined in scope of scenario objects may apply to Cucumber step definitions as well. Core layer of the framework will need some additional configurations and abstractions, but large part is going to stay untouched.

So it appears that Cucumber nicely fits in into existing architecture. There is still some work needed to translate java test methods into gherkin scenarios, but this is one time effort and absolutely beneficial for all team members. It is probably not too effort consuming as well, as long as good test coding practices were used during test development.

Gherkin scenarios

While test cases can be written in human understandable form by using gherkin, it doesn’t mean they can be created in totally freestyle way. A single Cucumber scenario is still a test, which translates directly to java code. If this is possible, feature files should be created by technical project members, who understand test framework architecture and/or reviewed by them before including into test suites. Apart from test framework documentation and java test development good practices available for everyone, it would be extremely helpful to document standards for gherkin scenarios as well.

One of rules, I would advise to put into standards, is to build scenarios from independent steps. This means that no test data can be passed between step definition methods on java level to keep it as much stateless as possible. All test data comes directly or indirectly from Cucumber scenario – all expectations should be clearly described in gherkin and passed to java from there. No step dependency means maximum step definition reusability in the future. If for some reason it is not possible to keep this rule working in the project, try to introduce another abstraction layer to pass required data between steps. Thanks to that it would be possible to avoid binding step definition classes to single use case and keep the code DRY.

Sample scenario, which has step dependencies:

Scenario: Add item to cart and verify Top Bar content
  When User adds item to cart
  Then Appropriate header is displayed in Top Bar

Having above scenario I need to create some logic which would extract item data in first step to reuse it in second step for header verification. Let’s try to fix this in following way:

Scenario: Add item to cart and verify Top Bar content
  When User adds Apple to cart
  Then Top Bar header displays "Apple (1)"

In this case I have everything given from scenario level – no need to pass anything between steps. I can create simple step which will add item to cart and second step to verify header content. What’s more, those steps can easily be parameterized and reused in many other test cases where header content needs to be verified.

Using Cucumber together with Selenium is a tough call especially for long e2e acceptance scenarios, but not impossible. By all means there should be standards defined for every aspect of the framework and strict layer separation needs to be maintained to make the framework as scalable as possible.

Summary

Cucumber definitely brings a lot of nice features, like easy to understand gherkin scenarios, nice reporting and support for BDD, but there are also a lot of traps, which can bring your solution down in long term. What I have learnt about Cucumber is that it is not actually ready to use framework architecture, which will allow you to create tests easily from scratch. If you start adding step definitions one by one, without any solid background, it will probably collapse at some point. From my perspective it is better to start organize standalone framework, keeping in mind all good practices, layer separation, stateless page objects, etc. When that kind of skeleton is ready, it is surprisingly easy to introduce Cucumber and make it rock solid solution for test development. The only thing left to keep in mind is that certain discipline is required when writing new feature files, because scenario semantics shapes framework implementation, just the same way as any other test written in java.

Visit my github repo https://github.com/bdrzew/netenttest to check basic Cucumber/Selenium test framework implementation in java.

Bartek Drzewiński

Did you like this article?

Building Selenium framework in java (part III) - how do you fit Cucumber in there