Skip to content

Testing with Cucumber, how to

Edwin Vásquez edited this page Jan 31, 2017 · 3 revisions

#Pre-Requisites

  • Install nodejs sudo apt-get install nodejs
  • Install npm sudo apt-get install npm

#Install Cucumber npm install --save-dev cucumber@latest

#Setting up the tests For this we are going to use a simple math example which goes by the following structure

  • Create a folder named features in the root of your project
  • Create a file named addition.feature inside the features folder
  • Create a folder inside features folder named step_definitions
  • Create a file inside step_definitions named addition.js

Your project structure should now look like this:

MyProject
├── features
    ├── addition.feature
    └── step_definitions
        └── addition.js

###Explaining a bit the structure:

  • By default cucumber will look for the features folder as the root folder of your tests but you can have a custom directory, we'll see how it's done later.
  • All of the *.feature files should contain a single feature, they usually contain a list of scenarios and steps that will be matched against the step definitions.
  • The step_definitions folder contains the method definitions of the features, as a convention they should match the name of the feature.

Let's look at the following example, this will be the content of our addition.feature file for now:

Feature: Simple maths
  In order to do maths
  As a developer
  I want to increment variables

  Scenario: easy maths
    Given a variable set to 1
    When I increment the variable by 1
    Then the variable should contain 2

Let's break down some keywords:

  • Feature: this will be the starting keyword of our .feature files where we will describe the name of the feature to test. Below we can write down a narrative description of the feature for example As a [role], I want [feature], so that I [can do something].
  • Scenario: describes the different scenarios to test.
  • Given: is the pre-condition and it should be used to put the system in the desired state before the user or an external system interacts with our system.
  • When: describes an action the user performs.
  • Then: the purpose of this it's to see the expected results.

Cucumber treats Given, When and Then the same way but should be used as described to give a better context.

Now let's define our addition.js file:

'use strict';

module.exports = function() {
  var variable = 0;

  function setTo(number) {
    variable = parseInt(number);
  }

  function incrementBy(number) {
    variable += parseInt(number);
  }

  this.Given("a variable set to $n", function(number, callback) {
    setTo(number);
    callback();
  });

  this.When("I increment the variable by $n", function(number, callback) {
    incrementBy(number);
    callback();
  });

  this.Then("the variable should contain $n", function(number, callback) {
    if (variable != parseInt(number))
      var err = new Error('Variable should contain ' + number +
        ' but it contains ' + variable + '.');
    callback(err);
  });
};

As explained before Cucumber will compare the steps described in our feature scenario with a step definition that contains the same steps, so we could name our file whatever we want and it will be executed anyway, it's the step description what matters. Also as you can see variables can be passed through $variables.

Now let's execute our tests with the following command: node ./node_modules/.bin/cucumber.js if you have a custom directory you can do node node_modules/.bin/cucumber.js my/custom/directory this could be added as a script in our package.json file, for example:

"scripts": {
  "feature-test": "node_modules/.bin/cucumber.js"
}

Now we can just do npm run feature-test. Our output now should look like this:

tests

We can do more complex stuff, add the following at the end of to our addition.feature

  Scenario Outline: much more complex stuff
    Given a variable set to <var>
    When I increment the variable by <increment>
    Then the variable should contain <result>

    Examples:
      | var | increment | result |
      | 100 |         5 |    105 |
      |  99 |      1234 |   1333 |
      |  12 |         5 |     18 |

As you can see we can add a set of variables to our Scenario using Scenario Outline which will execute the scenario as much Examples we pass to it, this will avoid repeating the same scenario but with different data. We have made the test fail on purpose on the last example so you can see how it works.

Now when executing npm run test-feature we should see the following: tests2

#Writing good tests

  • Feature should be only one line describing the story.
  • Scenario should be based on acceptance criteria of user story.
  • Scenarios should be kept independent, they should not depend on other scenarios.
  • Before writing a Scenario Outline ask yourself if it's necessary to repeat this scenario 'x' amount of times with different data.
  • Remember that this also serves as documentation so we should describe behavior at a higher level using a declarative form not imperative. For example: use When I log in instead of When I click on the "Login" button. This will allow us to abstract the implementation details of our application.
  • Keep the step definitions unique, otherwise you could encounter an ambiguous match exception. If you have described two different parts of the system with the exact same wording, you might be talking about the same thing and you might need some refactoring to do.
  • Avoid hard-coding parameters in your code, this also applies to sites URL's.
  • The tests should be written from the point of view of an architect, not of a developer.

#Sources https://github.com/cucumber/cucumber/wiki

https://saucelabs.com/blog/write-great-cucumber-tests

https://www.coveros.com/writing-effective-cucumber-tests/

Clone this wiki locally