-
Notifications
You must be signed in to change notification settings - Fork 1
Testing with Cucumber, how to
#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 thefeatures
folder - Create a folder inside
features
folder namedstep_definitions
- Create a file inside
step_definitions
namedaddition.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 exampleAs 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:
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:
#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 ofWhen 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