Node.js-code testen met Mocha en Chai

Introductie

Het schrijven van unit-tests is iets wat zowel beginners als doorgewinterde ingenieurs doorgaans uitstellen tot latere ontwikkelingsfasen, maar toch zijn ze de sleutel tot stabiele en robuuste softwareontwikkeling.

Het uitgangspunt van testgestuurde ontwikkeling (TDD) is het schrijven van uw tests, zelfs voordat u begint met coderen. Dat is een geweldig doel om naar te streven, maar het vergt veel discipline en planning als je de principes ervan probeert te volgen! Om dit hele proces een stuk eenvoudiger te maken, kun je gebruik maken van eenvoudig te gebruiken en krachtige test- en beweringsframeworks, zoals Mocha en Chai.

In dit artikel laten we u eerst kennismaken met deze twee bibliotheken en laten we u vervolgens zien hoe u ze samen kunt gebruiken om snel leesbare en functionele unit-tests te maken.

Chai

Chai is een beweringsbibliotheek die zowel de BDD (gedragsgestuurde ontwikkeling) en TDD (testgestuurde ontwikkeling) programmeerstijlen voor het testen van code, en is bedoeld om te worden gecombineerd met een testbibliotheek waarmee u tests kunt organiseren. Het wordt heel vaak gecombineerd met mokka.

Het heeft drie hoofd-API's:

  • should
  • expect
  • assert

var.should.equal(var2)


expect.var.to.be.equal(var2)


assert.equal(var1, var2)

In dit artikel zullen we ons concentreren op de BDD-stijl met behulp van Chai's expect interface, hoewel het gebruik van andere interfaces/stijlen volgens uw eigen intuรฏtie prima is. De assert interface is het meest voorkomende TDD-beweringframework.

expect gebruikt een zeer natuurlijke taal-API om uw beweringen te schrijven, waardoor uw tests later gemakkelijker te schrijven en te verbeteren zijn. Dit wordt gedaan door getters aan elkaar te koppelen om de bewering te creรซren en uit te voeren, waardoor het gemakkelijker wordt om vereisten in code te vertalen:

let user = {name: 'Scott'};


expect(user).to.have.property('name');

Opmerking: Zie je hoe je de bewering vrijwel in natuurlijke taal kunt lezen en kunt begrijpen wat er aan de hand is? Dat is een van de belangrijkste voordelen van het gebruik van een beweringsbibliotheek zoals Chai!

Nog een paar voorbeelden van deze getters zijn:

  • to
  • be
  • is
  • and
  • has
  • have

Een flink aantal van deze getters kunnen aan elkaar worden gekoppeld en worden gebruikt met beweringsmethoden zoals true, ok, exist en empty om enkele complexe beweringen in slechts รฉรฉn regel te creรซren:

"use strict";

const expect = require('chai').expect;


expect({}).to.exist;
expect(26).to.equal(26);
expect(false).to.be.false;
expect('hello').to.be.string;


expect([1, 2, 3]).to.not.be.empty;


expect([1, 2, 3]).to.have.length.of.at.least(3);

Opmerking: Een volledige lijst van de beschikbare methoden kunt u vinden hier.

Misschien wilt u ook de lijst met beschikbare opties bekijken plugins voor Chai. Deze maken het veel eenvoudiger om complexere functies te testen.

Nemen chai-http Dit is bijvoorbeeld een plug-in waarmee u serverroutes kunt testen:

"use strict";

const chai = require('chai');
const chaiHttp = require('chai-http');

chai.use(chaiHttp);

chai.request(app)
    .put('/api/auth')
    .send({username: '[email protected]', password: 'abc123'})
    .end(function(err, res) {
        expect(err).to.be.null;
        expect(res).to.have.status(200);
    });

Testcases organiseren met Mokka โ€“ beschrijven() en it()

Mocha is een testframework voor Node dat u de flexibiliteit geeft om asynchrone (of synchrone) code serieel uit te voeren. Alle niet-afgevangen uitzonderingen worden weergegeven naast de testcase waarin deze is gegooid, waardoor het gemakkelijk wordt om precies te identificeren wat er is mislukt en waarom.

Het wordt geadviseerd om Mocha wereldwijd te installeren:

$ npm install mocha -g

Je wilt dat het een globale installatie is sinds de mocha opdracht wordt gebruikt om de tests voor het project in uw lokale map uit te voeren.

Wat doet dit stukje code?

it() moet X teruggeven. it() definieert testgevallen, en Mocha zal ze allemaal uitvoeren it() als unittest. We kunnen meerdere unit-tests organiseren describe() een gemeenschappelijke functionaliteit, en zo Mocha-tests structureren.

Dit kan waarschijnlijk het beste worden beschreven met een concreet voorbeeld:

"use strict";
const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });
    });
});

In het describe() methode hebben we a gedefinieerd test naam, Genaamd #abs(). U kunt ook afzonderlijk tests uitvoeren op basis van hun naam. Dit wordt later besproken.

Opmerking: Met Mokka-testen is dat niet nodig require() een van de Mocha-methoden. Deze methoden worden globaal aangeboden wanneer ze worden uitgevoerd met de mocha opdracht.

Om deze tests uit te voeren, slaat u uw bestand op en gebruikt u de mocha opdracht:

$ mocha .

  Math
    #abs()
      โœ“ should return positive value of given number 


  1 passing (9ms)

De output is een overzicht van de uitgevoerde tests en hun resultaten. Merk op hoe het genest is describe() oproepen worden overgedragen naar de resultaatuitvoer. Het is handig om alle tests voor een bepaalde methode of functie samen te nesten.

Deze methoden vormen de basis voor het Mocha-testraamwerk. Gebruik ze om uw toetsen samen te stellen en te organiseren zoals u dat wilt. We zullen hiervan een voorbeeld zien in de volgende sectie.

Testen schrijven met mokka en chai

De aanbevolen manier om uw tests binnen uw project te organiseren, is door ze allemaal in hun eigen project te plaatsen /test map. Standaard controleert Mocha op unit-tests met behulp van de klodders ./test/*.js en ./test/*.coffee. Van daaruit zal het elk bestand laden en uitvoeren dat het describe() methode.

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

Het is gebruikelijk om de testbestanden te voorzien van het achtervoegsel .test.js voor de bronbestanden die Mocha-tests bevatten:

โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ lib
โ”‚   โ”œโ”€โ”€ db.js
โ”‚   โ”œโ”€โ”€ models.js
โ”‚   โ””โ”€โ”€ util.js
โ””โ”€โ”€ test
    โ”œโ”€โ”€ db.test.js
    โ”œโ”€โ”€ models.test.js
    โ”œโ”€โ”€ util.test.js
    โ””โ”€โ”€ util.js

util.js in de test directory zou geen unit-tests bevatten, alleen hulpprogramma-functies om te helpen bij het testen.

Note: U kunt elke structuur gebruiken die voor u zinvol is, de unit-tests worden automatisch opgepakt.

Als het gaat om het daadwerkelijk schrijven van de tests, helpt het om ze te organiseren met behulp van de describe() methoden. U kunt ze ordenen op kenmerk, functie, bestand of elk ander willekeurig niveau. Een testbestand dat is georganiseerd om de werking op functieniveau te beschrijven, ziet er bijvoorbeeld als volgt uit:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });
});

Als u de tests uitvoert, krijgt u dan de uitvoer:

$ mocha .

  Math
    #abs()
      โœ“ should return positive value of given negative number 
      โœ“ should return positive value of given positive number 
      โœ“ should return 0 given 0 


  3 passing (11ms)

Als je het nog verder uitbreidt, kun je zelfs tests voor meerdere methoden in รฉรฉn bestand hebben. In dit geval worden de methoden gegroepeerd op basis van de Math voorwerp:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });

    describe('#sqrt()', function() {
        it('should return the square root of a given positive number', function() {
            expect(Math.sqrt(25)).to.be.equal(5);
        });

        it('should return NaN for a given negative number', function() {
            expect(Math.sqrt(-9)).to.be.NaN;
        });

        it('should return 0 given 0', function() {
            expect(Math.sqrt(0)).to.be.equal(0);
        });
    });
});

Wat resulteert in:

$ mocha .

  Math
    #abs()
      โœ“ should return positive value of given negative number 
      โœ“ should return positive value of given positive number 
      โœ“ should return 0 given 0 
    #sqrt()
      โœ“ should return the square root of a given positive number 
      โœ“ should return NaN for a given negative number 
      โœ“ should return 0 given 0 


  6 passing (10ms)

Mokkahaken โ€“ before(), after(), beforeEach() en afterEach()

Toegegeven, de meeste unit-tests zijn niet zo eenvoudig. Vaak heb je waarschijnlijk andere bronnen nodig om je tests uit te voeren, zoals een database of een andere externe bron (of een namaak/stub daarvan). Om dit in te stellen, kunnen we een of meer van de volgende gebruiken Mokka haak methoden:

  • before(): Wordt uitgevoerd vรณรณr alle tests in het gegeven blok
  • beforeEach(): Wordt uitgevoerd vรณรณr elke test in het gegeven blok
  • after(): Wordt uitgevoerd na alle tests in het opgegeven blok
  • afterEach(): Wordt uitgevoerd na elke test in het gegeven blok

Deze haken zijn de perfecte plek voor het uitvoeren van op- en afbouwwerkzaamheden die nodig zijn voor uw tests. Een van de meest voorkomende gebruiksscenario's is het tot stand brengen van een verbinding met uw database voordat u de tests uitvoert:

"use strict";

const expect = require('chai').expect;
let User = require('../models').User;

describe('Users', function() {

    let database = null;

    before(function(done) {
        
    });

    afterEach(function(done) {
        
    });

    describe('#save()', function() {
        it('should save User data to database', function(done) {
            
        });
    });

    describe('#load()', function() {
        it('should load User data from database', function(done) {
            
        });
    });
});

Voor elke van de tests wordt uitgevoerd, wordt de functie naar onze verzonden before() methode wordt uitgevoerd (en slechts รฉรฉn keer tijdens de tests), waardoor een verbinding met de database tot stand wordt gebracht. Zodra dit is gebeurd, worden onze testsuites uitgevoerd.

Omdat we niet willen dat de gegevens van de ene testsuite onze andere tests beรฏnvloeden, moeten we de gegevens uit onze database wissen nadat elke suite is uitgevoerd. Dit is wat afterEach() is voor. We gebruiken deze hook om daarna alle databasegegevens te wissen elk testcase is uitgevoerd, zodat we met een schone lei kunnen beginnen voor de volgende tests.

Mokka-testen uitvoeren

In de meeste gevallen is dit onderdeel vrij eenvoudig. Ervan uitgaande dat je Mocha al hebt geรฏnstalleerd en naar de projectmap bent genavigeerd, hoeven de meeste projecten alleen de mocha commando zonder argumenten om hun tests uit te voeren:

$ mocha


  Math
    #abs()
      โœ“ should return positive value of given negative number 
      โœ“ should return positive value of given positive number 
      โœ“ should return 0 given 0 
    #sqrt()
      โœ“ should return the square root of a given positive number 
      โœ“ should return NaN for a given negative number 
      โœ“ should return 0 given 0 


  6 passing (10ms)

Dit is iets anders dan onze vorige voorbeelden, omdat we Mocha niet hoefden te vertellen waar onze tests zich bevonden. In dit voorbeeld bevindt de testcode zich op de verwachte locatie van /test.

Er zijn echter enkele handige opties die u mogelijk wilt gebruiken bij het uitvoeren van tests. Als sommige van uw tests bijvoorbeeld mislukken, wilt u waarschijnlijk niet de hele suite uitvoeren telkens wanneer u een wijziging aanbrengt. Bij sommige projecten kan het voltooien van de volledige testsuite enkele minuten duren. Dat is een hoop tijdverspilling als je eigenlijk maar รฉรฉn test hoeft uit te voeren.

Voor dit soort gevallen zou je dat wel moeten doen vertel Mocha welke tests je moet uitvoeren. Dit kan met behulp van de -g or -f opties.

Om individuele tests uit te voeren, kunt u de -g vlag en voeg een gemeenschappelijk patroon toe tussen de tests die u wilt uitvoeren. Als u bijvoorbeeld de #sqrt() testen:

$ mocha -g sqrt

  Math
    #sqrt()
      โœ“ should return the square root of a given positive number 
      โœ“ should return NaN for a given negative number 
      โœ“ should return 0 given 0 


  3 passing (10ms)

Merk op dat de #abs() tests waren niet opgenomen in deze run. Als u dienovereenkomstig plant met uw testnamen, kan deze optie worden gebruikt om alleen specifieke delen van uw tests uit te voeren.

Dit zijn echter niet de enige nuttige opties. Hier zijn nog een paar opties voor mokka die je misschien wilt bekijken:

  • --invert: Inverteert -g en -f lucifers
  • --recursive: Inclusief submappen
  • --harmony: schakel alle harmoniefuncties in Node in

Note: U kunt de volledige lijst met opties bekijken met behulp van de mocha -h commando, of aan deze pagina.

Waar kunt u meer leren? Dit onderwerp omvat veel meer dan we in een kort artikel kunnen behandelen, dus als je meer wilt weten, raden we je aan de officiรซle Mocha en Chai documentatie.

Conclusie

Houd er rekening mee dat zowel Mocha als Chai kunnen worden gebruikt voor het testen van vrijwel elk type Node-project, of het nu een bibliotheek, een opdrachtregelprogramma of zelfs een website is. Door gebruik te maken van de verschillende opties en plug-ins die voor u beschikbaar zijn, zou u vrij gemakkelijk aan uw testbehoeften moeten kunnen voldoen. Elk van deze bibliotheken is erg handig voor het valideren van uw code en zou in vrijwel al uw Node-projecten moeten worden gebruikt.

Hopelijk heeft dit als een nuttige introductie tot Mokka en Chai gediend. Er valt nog veel meer te leren dan wat ik hier heb gepresenteerd, dus bekijk zeker de documentatie voor meer informatie.

Tijdstempel:

Meer van Stapelmisbruik