Tests fonctionnels & Backbone

Kajan Sivaramalingam

Développeur web freelance

@KajanSiva

http://kajansiva.com

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

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