23 mai tests
Transcription
23 mai tests
Strasbourg Node.js Tests en Javascript et TDD Pas de tests = des bugs Pourquoi tester ? ● Un bug en prod = ○ ○ ○ ○ Context switching Analyse plus complexe Stress et fatigue Dépréciation de l’image Types de tests ● Tests manuels : exploratoires, usabilité, UAT ● Tests automatisés : unitaires, intégration ● Tests manuels et automatisés : cas nominaux et nouvelles fonctionnalités ● Tests techniques : sécurité, charge, robustesse => Tous ces types de tests sont utiles Pourquoi tester automatiquement ? ● Plus rapides que les tests manuels ● Pour améliorer le “time to market” ● Pour livrer plus rapidement et sereinement Quelle stratégie de tests ? ● Cycle en V ? ○ ○ ○ ○ tests en fin de projet feedback sur problèmes de qualité trop tardif tests de bout en bout, complexes et coûteux on est en retard, on peut déscoper les tests ● Ce n’est pas au développeur de tester ? ○ dé-responsabilisation ○ perte de temps sur les problèmes évidents LA bonne stratégie de tests ● Au coeur de l’équipe de développement ● Les tests sont faits au plus tôt ● Les tests les plus pertinents sont automatisés Pyramide des tests Quels outils en Node.js ? ● Exécuter le test ○ Mocha ● Simuler le comportement ○ Nock : les mocks http ○ Rewire : ré-écriture de comportement ○ Sinon.js : les mocks ● Vérifier les résultats du test ○ Chai Mocha test.js describe('Array', function() { describe('#indexOf()', function () { it('should return -1 when the value is not present', function () { assert.equal(-1, [1,2,3].indexOf(5)); assert.equal(-1, [1,2,3].indexOf(0)); }); }); }); Mocha $ mocha test.js dans la console Array #indexOf() ✓ should return -1 when the value is not present 1 passing (11ms) Mocha : gestion de l’asynchrone describe('User', function() { describe('#save()', function() { it('should save without error', function(done) { var user = new User('Luna'); user.save(function(err) { if (err) throw err; done(); }); }); }); }); Mocha : hooks before(function() { console.log(‘Debut de la suite de tests’); }); // ou after, beforeEach, afterEach Mocha : inclusion / exclusion ● describe.only, describe.skip ● it.only, it.skip ● Exemple d’exclusion de test : it.skip('should save without error', function(done) { // ... }); Chai / should chai.should(); foo.should.be.a('string'); foo.should.equal('bar'); foo.should.have.length(3); tea.should.have.property('flavors').with.length(3); Chai / expect 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); Chai / assert var assert = chai.assert; assert.typeOf(foo, 'string'); assert.equal(foo, 'bar'); assert.lengthOf(foo, 3) assert.property(tea, 'flavors'); assert.lengthOf(tea.flavors, 3); Tester avec Nock nock(baseUrl) .get(‘/employees/count’) .reply(200, {count:1986}); Nock : simuler une erreur nock(baseUrl) .get(‘/employees/count’) .reply(500, {error:’unexpected error’}); Nock : simuler un timeout nock(baseUrl) .get(‘/employees/count’) .delayConnection(2000) .delay(3000) .reply(200, {count:1986}); Nock : interdire les connexions nock.disableNetConnect() Nock : vérifier les appels var countScope = nock(baseUrl) .get(‘/employees/count’) .reply(200, {count:1986}); // … countScope.isDone(); Nock : recorder dans le test nock.recorder.rec(); dans la console <<<<<<-- cut here -->>>>>> nock('http://localhost:3000') .get('/employees/count') .reply(200, {"count":1200}, { 'xpowered-by': 'Express', 'contenttype': 'application/json; charset=utf-8', 'content-length': '14',connection: 'keep-alive' }); <<<<<<-- cut here -->>>>>> Rewire : code à tester var fs = require("fs"), path = "/somewhere/on/the/disk"; lib/myModule.js function readFile(cb) { console.log("Reading from file system ..."); fs.readFile(path, "utf8", cb); } exports.readFile = readFile; Rewire : le test var rewire = require("rewire"); var myModule = rewire("../lib/myModule.js"); myModule.__set__("path", "/dev/null"); myModule.__get__("path"); // = '/dev/null' myModule.readFile(function (err, data) { console.log(data); }); test/myModule.test.js Sinon.js var myAPI = { method: function () { } }; var mock = sinon.mock(myAPI); mock.expects("method").once().returns(42); console.log(myAPI.method()); Test Driven Development Test, Code, Refactor 1. 2. 3. 4. Ecrire un test en échec Faire en sorte que le test passe Refactoring Recommencer TDD : pourquoi ? ● ● ● ● ● Prise de recul avant de coder Feedback immédiat Code testable, lisible et propre Bonne couverture de tests On se concentre sur des problèmes simples à chaque itération ● Impact positif sur la productivité Quelques stats ● Etude d’IBM sur l’impact de la productivité ○ Temps de développement plus long : 15-30% ○ Moins de bugs : 40-90% ● Importance du “clean code” par Uncle Bob ○ 90% de temps à lire du code ○ 10% de temps à écrire du code Atelier Poker Hands Règles de l’atelier Poker Hands ● Se poser la bonne question à chaque étape : ○ Test : quel est le prochain cas à tester ? ○ Code : quelle est l’implémentation la plus simple ? ○ Refactor : Est-il possible de faire du refactoring? ● Soignez le code des tests ● Ne grillez pas les étapes