fr.romain:blog:3.0

Un blog qu'il est bien pour le Java

Devoxx France 2013 - Jour 1

| Comments

Devoxx France

Enfin, ça y est ! La deuxième édition de la conférence Devoxx France a débuté. Comme l’année dernière, la conférence se déroule sur trois jours. Le mercredi est essentiellement constituée de démonstrations, de laboratoires, de mises en pratique d’un outil ou d’un langage, de Tools in Action. Ma journée débute donc avec une université sur les tests en JavaScript. L’après-midi contiendra quelques surprises, dont… un minitel :)

Le fantôme, le zombie et Testacular, panorama des outils de tests pour application web moderne

Qui fait vraiment des tests ?

Photo par @binout

Pour commencer la journée et la conférence, Jean-Laurent de Morhlon (@morlhon) et Pierre Gayvallet (@wayofspark) nous proposent un tour d’horizon de ce qui se fait autour des tests JavaScript.

Tout d’abord, un rappel des différents types de tests

  • Tests unitaires : il s’agit ici de tests techniques. On les exécutera plutôt en isolation, c’est-à-dire côté en supprimant le maximum de choses autour du code : pas de base de données, de navigateur web, d’accès réseau, etc.
  • Tests d’intégration : nous restons dans les techniques techniques, mais ici nous voulons mettre l’ensemble de l’application en test.
  • Tests d’acceptance : ce sont avant tout des tests fonctionnels. Nous pouvons utiliser le BDD (Behavior Driven Development). Toutefois, ces tests doivent représenter une petite partie de l’ensemble des tests.

Technique de l’outside-in :

  • On écrit un test d’acceptance qui va échouer.
  • Ensuite, on écrit un test unitaire qui va également échouer.
  • Puis on code de façon à faire passer le test simplement.
  • Une fois le test unitaire réussit, on procède au refactoring.
  • Une fois que le test unitaire est au vert et que le refactoring est terminé, on peut terminer en faisant en sorte que le test d’acceptance réussisse.

Un peu de vocabulaire maintenant : un navigateur headless (”sans tête”) est un navigateur sans interface graphique. Cela servira beaucoup pour les tests, la partie graphique étant éliminée, nous gagnons ainsi beaucoup de temps. Quelques exemples : PhantomJS, HtmlUnit, Zombie.js…

PhantomJS

PhantomJS

PhantomJS, un navigateur headless dispose d’un vrai rendering (pas d’émulation), rapide, et offre une API JavaScript très complète.

Voici un exemple de code avec PhantomJS :

1
2
3
4
5
6
7
console.log('Loading a web page');
var page = require('webpage').create();
var url = 'http://www.phantomjs.org/';
page.open(url, function (status) {
    //Page is loaded!
    phantom.exit();
});

L’une des particularité de PhantomJS est son double contexte d’exécution : client et serveur. Cela implique parfois des problèmes de communication entre les deux contextes, ce qui est souvent source d’erreur.

La gestion du rendering de PhantomJS supporte quasiment tous les standards HTML5 et CSS3, avec quelques limites toutefois : pas de support de Flash (ô mon dieu :) ), pas de CSS 3D, de géolocalisation, WebGL, etc. Son écosystème est assez riche : GhostWriter (qui implémente la spécification WebDriver), des runners de tests (Poltergeist, Mocha, etc.), des frameworks de tests (Lotte, WebSpecter, CasperJS, etc.), mais aussi des outils pour réaliser des screenshots (capturejs, node-webshot…)

CasperJS

CasperJS

CasperJS est une surcouche de PhantomJS pour ajouter ce qui manque à ce dernier :

  • Gestion des callbacks, de l’asynchronisme
  • API fluide (fluent API)
  • Méthodes d’intéraction avec la page (support du clavier, etc.)
  • Framework de tests

Par exemple, le code suivant :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var page = require('webpage').create();

page.open(url1, function(status) {
    if (status == "fail") phantom.exit();
    page.open(url2, function(status) {
        if (status == "fail") phantom.exit();
        page.open(url3, function(status) {
            if (status == "fail") phantom.exit();
            page.open(url4, function(status) {
                if (status == "fail") phantom.exit();
                // Can I stop, now?
            });
        });
    });
});

s’écrira plus simplement avec CasperJS :

1
2
3
4
5
6
7
8
var casper = require('casper').create();

casper.start(url1);
casper.thenOpen(url2);
casper.thenOpen(url3);
casper.thenOpen(url4);

casper.run();

Il faut noter qu’avec la version 1.1 de CasperJS (pas encore sortie), l’écriture des tests sera simplifiée, en particulier pour ce qui concerne le code à exécuter avant ou après des tests (setUp et `tearDown).

S’ensuit une démonstration de l’outil CasperJS, pour tester de façon fluide est très simple des interactions sur un site web marchant : tests basiques d’une page (vérification d’un titre, du contenu), simulation de clics pour ajouter des éléments dans le panier, test de la validation d’un formulaire, etc. Point sympathique, il est possible de demander à CasperJS de réaliser une capture d’écran durant un test et de le copier dans un fichier avec une commande simple : casper.capture("mon_image.png"); On peut donc faire du Screenshot Driven Development :)

Zombie.js

ZombieJS

ZombieJS est un navigateur headless, qui tourne sur node.js, et qui repose sur des bibliothèque d’émulation (c’est un avantage mais aussi un inconvénient). Ce n’est donc pas un vrai navigateur, bien qu’il supporte la plupart des fonctionnalités des navigateurs actuels : HTML5, sélecteurs CSS3, cookier, web storage, ajax, etc. Il se base sur certaines librairies tierces, telles que :

  • JSDom
  • HTML5
  • Sizzle.js (sélecteurs CSS)

L’API de Zombie.js est fluide, ce qui permet de rendre le code plus lisible (encore plus en utilisant CoffeeScript). Voici un exemple de code avec Zombie.js :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var Browser = require("zombie");
var assert = require("assert");

// Load the page from localhost
browser = new Browser()
browser.visit("http://localhost:3000/", function () {

  // Fill email, password and submit form
  browser.
    fill("email", "zombie@underworld.dead").
    fill("password", "eat-the-living").
    pressButton("Sign Me Up!", function() {

      // Form submitted, new page loaded.
      assert.ok(browser.success);
      assert.equal(browser.text("title"), "Welcome To Brains Depot");

    })

});

Un autre exemple de test avec les sélecteurs CSS :

1
brower.queryAll("#content > .produit").length.should.equal(7);

Avec Zombie, le code devient très lisible, ultra rapide. Toutefois, il a quelques défauts (assez importants pour certains) :

  • Emule un navigateur.
  • Difficile à intégrer dans un build java.
  • Difficile à faire tourner sur Windows (aie !).
  • Le développement est quelque peu en berne (aie aussi !).
  • Les erreurs sont parfois cryptiques.

Jean-Laurent passe ensuite à une démonstration de l’outil avec CoffeeScript.

QUnit

QUnit

QUnit est une librairie de tests JavaScript plus proche des JUnit, avec le système des assert. On est ici plutôt à destination des tests unitaires, pour faire du TDD. L’écosystème de QUnit est assez riche, il est également possible d’ajouter de nouvelles assertions (par défaut, QUnit n’en propose qu’une toute petite poignée) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Code du plugin QUnit closeEnough (https://github.com/jquery/qunit/tree/master/addons/close-enough)
QUnit.extend( QUnit.assert, {

  /**
  * Checks that the first two arguments are equal, or are numbers close enough to be considered equal
  * based on a specified maximum allowable difference.
  */
  close: function(actual, expected, maxDifference, message) {
      var passes = (actual === expected) || Math.abs(actual - expected) <= maxDifference;
      QUnit.push(passes, actual, expected, message);
  },

  /**
  * Checks that the first two arguments are numbers with differences greater than the specified
  * minimum difference.
  */
  notClose: function(actual, expected, minDifference, message) {
      QUnit.push(Math.abs(actual - expected) > minDifference, actual, expected, message);
  }
});

L’utilisation de cette nouvelle assertion doit passer par l’objet assert :

1
2
3
4
test('Example unit test', function(assert) {
    assert.close(3.141, Math.PI, 0.001);
    assert.notClose(3.1, Math.PI, 0.001);
}

Sinon.js

Cette librairie de tests a le gros avantage de pouvoir mocker pas mal de choses, dont les timers, des servers, des appels Ajax. Il dispose également d’une API assez complète pour les espions (spy) ou les stubs. Un petit exemple :

1
2
3
4
5
6
7
8
9
10
it("calls original function with right this and args", function () {
    var callback = sinon.spy();
    var proxy = once(callback);
    var obj = {};

    proxy.call(obj, 1, 2, 3);

    assert(callback.calledOn(obj));
    assert(callback.calledWith(1, 2, 3));
});

Un autre exemple, en mockant une requête Ajax :

1
2
3
4
5
6
7
8
9
10
11
12
13
after(function () {
    // When the test either fails or passes, restore the original
    // jQuery ajax function (Sinon.JS also provides tools to help
    // test frameworks automate clean-up like this)
    jQuery.ajax.restore();
});

it("makes a GET request for todo items", function () {
    sinon.stub(jQuery, "ajax");
    getTodos(42, sinon.spy());

    assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});

Karma (aka Testacular)

Karma (anciennement appelé Testacular) est un lanceur de tests multi-navigateurs, tournant sur node.js. Il a été développé par l’équipe d’AngularJS (Google). Il propose également des adaptateurs pour supporter différents frameworks de tests : Mocha, Jasmine, QUnit ou Angular Scenario.

Chai.js

Chaijs

ChaiJS est une toute petite librairie d’assertions. Elle propose 3 types d’assertions :

Le type Assert :

1
2
3
4
5
6
7
var assert = chai.assert;

assert.typeOf(foo, 'string');
assert.equal(foo, 'bar');
assert.lengthOf(foo, 3)
assert.property(tea, 'favors');
assert.lengthOf(tea.flavors, 3);

Le type Expect :

1
2
3
4
5
6
var expect = chai.expect;

expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(tea).to.have.property('flavors').with.length(3);

Ou encore le type du Should :

1
2
3
4
5
6
chai.should();

foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
tea.should.have.property('flavors').with.length(3);

Mocha

Mocha

Mocha est un framework de test, tourne sur Node.js ou dans un navigateur. Il s’intègre parfaitement avec beaucoup d’autres choses : Jenkins, TeamCity, des outils comme chai.js.

JSCover

JSCover (anciennement JsCoverage) permet de mesurer la couverture de code par les tests JS. Il offre également un export de type Cobertura, ce qui lui permet son intégration dans Jenkins (et a priori Sonar ?).

Plato

Plato est un outil d’introspection des tests. Il donne ainsi un rapport détaillé du code JS, permet même d’estimer le nombre de bugs dans l’application :) Il met également en détails les erreurs levées par JsLint.

Voilà une très bonne présentation pour commencer Devoxx France, avec beaucoup de beaux outils à tester. Peut-être même trop, les trois heures ont paru bien courtes :)


Frontend live coding : tour d’horizon de l’outillage et des technos web d’aujourd’hui

Vidéo Parleys

Frédéric Camblor (@fcamblor) nous propose un tour d’horizon des outils liés au développement web :

  • Yeoman / Grunt : orchestrateur des développements web ;
  • Sass / Compass : surcouche à CSS permettant notamment de variabiliser les feuilles de style ;
  • Bower : provisionneur de librairies JavaScript ;
  • RequireJS : injecteur de dépendances JavaScript à la demande ;
  • Handlebars : moteur de templating coté client ;
  • BackboneJS : framework MVC qui permet d’améliorer la maintenabilité du code JavaScript ;
  • Un ensemble de tips de développement dans Chrome, dont vous ne soupçonnez peut-être pas l’existence.

Yeoman et Grunt

Yeoman

Premier outil présenté par Frédéric, Yeoman. C’est un ensemble d’outils pouvant jouer le rôle de scaffolder, c’est-à-dire qu’il va nous créer en un rien de temps une structure spécifique pour un projet, tout en forçant certaines bonnes pratiques (définition d’un cycle de vie pour l’application, exécution des tests, etc.). Quelque part, il y a pas mal de similitudes avec Maven ici.

Frédéric démarre par générer une structure adaptée à une webapp, via un générateur dédié. Il existe plusieurs autres générateurs, pour faire de l’Angular, du Testacular (enfin Karma), du Backbone, etc. La similitude avec les Maven archetype est saisissante ici. Donc une simple commande yo webapp permet de tout générer.

Une fois ceci généré, nous pouvons constater la présence d’un fichier gruntfile.js qui est utilisé par Grunt pour réaliser un certain nombre de tâches (“compilation”, tests, démarrage d’un serveur, etc.). Frédéric le compare là aussi à Maven ou Gradle. Dans les faits, je trouve plus que cela s’approche de Gradle et de son approche scriptée, mais bon. A en voir le contenu, cela est un peu cryptique dans un premier temps, mais Frédéric nous indique qu’il n’est guère nécessaire de s’y attarder. En effet, ça fonctionne, et c’est tout ce qu’on lui demande ! On pourra bien sûr décider de s’intéresser au contenu de ce fichier, si les besoins au sein du projet le nécessite.

SASS

SASS

SASS, à l’image de LESS est une surcharge du langage CSS pour en offrir des améliorations. Parmi celles-ci, on notera surtout :

  • @import qui permet d’importer un autre fichier CSS, et donc de bien segmenter son code CSS.
  • La possibilité d’imbriquer les classes (le nesting), offrant ainsi une bien meilleure lisibilité de son code, tout en l’architecturant mieux.
  • Les variables, pratique pour éviter les redondances, et faciliter le refactoring.
  • Des fonctions arithmétiques simples (on pourra faire $largeurPanneau + 10px par exemple).
  • Des mixins, sortes de fonction permettant de regrouper sous un même bloc un code redondant.

A noter qu’il existe un site, Compass qui permet de disposer de nombreux mixins pour SASS.

Bower

Bower est un module de gestion des dépendances, un peu à l’image de Maven. Le fichier component.json, que Frédéric avait généré via la commande yo webapp, est le descripteur des dépendances de notre projet web-app. Il est possible d’exécuter quelques commandes avec bower :

  • bower install pour installer en local les dépendances définies pour le projet. A noter que contrairement à Maven qui utilise un repository commun à tous les projets, Bower copie localement, pour chaque projet la liste des dépendances. Un peu dommage !
  • bower search recherche les dépendances présentes dans le registry Bower.
  • bower info XXX donne toutes les versions présentes pour la librairie spécifiée.

Il est également possible d’enregistrer sa propre librairie dans le registry de Bower, via une commande (bower register [mon package] [mon repo git]). Attention, il ne semble pas y avoir beaucoup de contrôles, et la librairie est de suite visible à tout le monde !

Un point important, le versioning des dépendances hébergées sur Bower est assez strict, et respecte le Semantic Versioning. Pour faire simple, une version est généralement constituée de 3 chiffres (x.y.z), où nous avons la version majeure (x), la version mineure (y) puis les bugfixes (z). Cela nous permet d’obtenir une certaine flexibilité dans la définition des dépendances. Par exemple, si on définit une version 1.2.x, cela signifie que l’on veut n’importe quelle version 1.2.*, et que si une nouvelle version bugfixe apparait, alors Bower pourra l’utiliser directement.

RequireJS

Require.js

Frédéric parle maintenant de Require.js, une librairie qui a l’avantage de pouvoir charger des fichiers JavaScript à la demande. On peut également y définir des dépendances (par exemple il faut la librairie foo.js puis bar.js avant d’exécuter mon code).

Handlebars

Handlebars

Il arrive fréquemment d’avoir besoin de recourir au templating, c’est-à-dire de placer de la donnée (généralement en format JSON) dans du code HTML (en particulier quand on doit itérer sur un ensemble d’éléments). Frédéric est parti pour utiliser Handlebars. Personnellement, j’ai plus l’habitude d’utiliser Mustache.js, mais les principes sont les mêmes.

Backbone.js

Backbone.js

Pour de multiples raisons, on peut être amené à développer toute une partie de l’application côté client. Ainsi, au lieu de développer le coeur de l’application côté serveur et de n’envoyer que la partie graphique au client, nous y envoyons un framework JavaScript, ainsi que toute une application côté client : la partie modèle, la partie controlleur et la partie vue se retrouvent dès lors sur le navigateur. Frédéric opte pour Backbone.js, mais il existe aussi Ember.js, ou le très à la mode Angular.js de Google. Un tel choix architectural n’est bien sûr pas à prendre à la légère, cela apporte certains avantages (rapidité, minimisation de l’utilisation de la bande passante, possibilité de faire fonctionner son application en mode déconnecté, etc.), mais il y a également des inconvénients, dont le principal à mon avis est la sécurité.

Rivets.js

Dernier choix de librairie de la session : Rivets.js pour réaliser du data-binding bi-directionnel. Cela est nécessaire pour qu’une modification au niveau du modèle soit immédiatement répercutée côté DOM, et qu’une modification côté DOM soit répercutée côté modèle. Cette librairie s’intègre parfaitement à Backbone.js, mais aurait été tout à fait inutile avec Angular, car ce dernier intègre nativement cette fonctionnalité de data-binding.

Pour résumer, cette deuxième université a été très intéressante aussi, car elle a montré une stack complète d’outils et de librairies pour le développement efficace d’une application en JavaScript. Seul bémol, la partie tests qui n’a pas été abordée. Toutefois, Frédéric nous avait prévenu au début qu’il n’était pas à l’aise dans ce domaine. De plus, l’université du matin en avait fait son thème principal, et cela aurait été sans doute redondant. J’aurais quand même apprécié de savoir quelles librairies de tests s’adaptaient le mieux avec la stack choisie par Frédéric.


3615 Cloud @ Devoxx

Le minitel, l'avenir de Maven ?

Voici une session complètement décalée. Nicolas Loof et Laurent Huet nous proposent d’intéragir avec une instance CloudBees grâce à… un minitel ! Oui, le minitel des années 80. Et sans trucage, juste du bricolage. Le montage est le suivant :

  • Un bon vieux minitel sert de console : saisie des commandes et affichage (textuel bien entendu).
  • Ensuite, un assemblage électronique réalisé par Laurent pour le connecter avec un Raspberry Pi.
  • Un Raspberry Pi qui va s’occuper de la partie “intelligente” des opérations.
  • Un MacBook Pro (celui de Nicolas, dont l’écran a rendu l’âme la semaine d’avant, grâce à un geste malheureux d’un enfant) pour la connexion à Internet. C’est aussi le MBP qui affichera la vidéo d’une caméra qui filme l’écran du minitel (eh oui, difficile de brancher un cable de vidéoprojecteur sur un minitel).

Durant la présentation, on nous explique le montage électronique, puis ils exécuteront les tâches suivantes :

  • Afficher le status de quelques jobs sur CloudBees, puis interagir avec eux : stopper ou démarrer ces jobs.
  • Faire un mvn package ! (ils le lanceront en mode offline bien sûr :) ).
  • Faire un commit avec git.

Bref, une session très agréable, bien que tout à fait inutile !

Good bad and ugly Maven - a puzzler session

In Maven dependencies hell

Nicolas Loof (encore lui), accompagné de son éternel ami Arnaud Héritier nous ont proposé le jeu ”Qui veut gagner des millions” mais à la sauce Maven. Au cours d’une série de 6 ou 7 questions, Nicolas présentait des situations plus ou moins compliquées avec Maven, souvent des problèmes de dépendances transitives avec des conflits de version. Arnaud, en bon candidat, devait donner la bonne réponse, avec parfois l’aide du public.

Dans une ambiance décontractée et sympathique, j’ai donc terminé la première journée de Devoxx, avant de me rendre au repas du soir des speakers.

Conclusion

Comme l’année dernière, la première journée a été très riche à Devoxx France. Celle-ci est généralement plus calme, car il y a moins de monde, les sessions sont plus longues, surtout quand on assiste à des universités. J’ai fait un choix très orienté sur JavaScript cette année, avec 6 heures de démo, de code et de tests. A vrai dire, le programme que j’avais initialement établi le matin était différent. Je comptais en effet aller d’abord suivre l’introduction à iOS pour un développeur Java puis le développement sur AngularJS, mais à ma grande déception il s’agissait d’universités et non de Labs (ou Hands On). Ne codant pas moi-même, je craignais de ne pas retenir grand chose pour iOS (je n’ai aucune connaissance dans ce langage), et je n’aurais sans doute pas appris grand chose de nouveau sur Angular.js, que j’ai déjà un peu manipulé.

Mon souhait pour Devoxx France 2014, ce serait que la conférence se déroule sur 4 jours :

  • 2 jours de Labs, Hands On et universités, mais avec une préférence pour les sessions on l’audience code;
  • 2 jours de conférences.

Sait-on jamais :)

Comments