Tests fonctionnels & Backbone


Trois catégories de tests
- Tests fonctionnels / E2E
- Tests d'intégration
- Tests unitaires
E2E
Intégration
Unitaire
Les tests fonctionnels
- Simulent les interactions utilisateurs
- Sont de type "boîte noire"
- Sont automatisés
Mais comment les implémenter ?
Trois piliers
Selenium
Cucumber
Gherkin
Selenium
- Librairie d'automatisation de navigateurs
- Depuis la v2, utilise le standard Webdriver
- Paquet NPM disponible (selenium-webdriver)
- Utilise des drivers pour les différents navigateurs

Cucumber
- Librairie d'exécution de tests automatisés
- Possède une version Javascript (cucumber.js)
- Utilise le langage Gherkin

Gherkin
- Proche du langage naturel
- Séparés en fonctionnalités avec des fichiers .feature
- Sont associés aux méthodes de définitions d'étapes
Des exemples ?
Feature: TodoMVC
Scenario: Add todo element
Given I have 0 element on the list
When I add task for 'Prepare the talk'
Then I have 1 element on the list
// ...
this.Given(/^I have (\d+) element on the list$/, function (number, done) {
this.driver.get('http://localhost:8080/examples/backbone/')
.then(function () {
this.waitFor('.todo-list');
this.driver.findElements({css: '.todo-list li'})
.then(function (elements) {
expect(elements.length).to.equal(parseInt(number));
done();
});
}.bind(this));
});
// ...
Les bases
Répétition de scénario
Feature: Cucumber scenario outline
Scenario Outline: Check authorized characters
Given I have <start_number> element on the list
When I add task for '<task>'
Then I have <end_number> element on the list
Examples:
| task | start_number | end_number |
| "Très grande phrase difficile à écrire" | 1 | 2 |
| "459 à _ \ % ^$ " | 2 | 3 |
| "Test" | 3 | 4 |
Pré-conditions
#...
Background:
Given I am on the list page
And I cleared the localStorage
#...
// ...
this.Given(/^I am on the list page$/, function (done) {
this.driver.get('http://localhost:8080/examples/backbone/')
.then(done);
});
// ...
this.Given(/^I cleared the localStorage$/, function (done) {
this.driver.executeScript(function () {
localStorage.clear();
});
done();
});
// ...
Tags
Pour lancer un scenario ou un feature spécifique :
./cucumber.js --tags <EXPRESSION>
- --tags @dev: taggués @dev
- --tags ~@dev: PAS taggués @dev
- --tags @foo,@bar: taggués avec @foo OU @bar
- --tags @foo --tags @bar: taggués avec @foo ET bar
Pattern "World" object
'use strict';
var fs = require('fs');
var webdriver = require('selenium-webdriver');
var chrome = require('selenium-webdriver/chrome');
var driver = new webdriver.Builder()
.withCapabilities(new chrome.Options().toCapabilities())
.build();
var getDriver = function() { return driver; };
var World = function World() {
this.webdriver = webdriver;
this.driver = driver;
this.By = webdriver.By;
this.waitFor = function(cssLocator, timeout) {
var waitTimeout = timeout || 20000;
return driver.wait(function() {
return driver.isElementPresent({ css: cssLocator });
}, waitTimeout);
};
};
module.exports.World = World;
module.exports.getDriver = getDriver;
Hooks : After / Before
'use strict';
var fs = require('fs');
var path = require('path');
var sanitize = require('sanitize-filename');
var myHooks = function () {
this.After(function (scenario) {
if (scenario.isFailed()) {
this.driver.takeScreenshot().then(function (data) {
var base64Data = data.replace(/^data:image\/png;base64,/, '');
fs.writeFile(
path.join(
'screenshots',
sanitize(scenario.getName() + '.png').replace(/ /g, '_')
),
base64Data,
'base64',
function (err) { if (err) console.log(err); }
);
});
}
});
};
module.exports = myHooks;
Reste de l'API de Selenium
Reste à creuser
- PageObject
- Librairies d'abstractions (Protractor, Nightwatch, ...)
- Industrialisation (Jenkins, SauceLabs, ...)
Des questions ?
Tests fonctionnels & Backbone
By Kajan Siva
Tests fonctionnels & Backbone
Talk d'introduction aux tests fonctionnels, présenté au meetup Backbone.js Paris le 22/06/2016.
- 528