Test af Node.js-kode med Mocha og Chai

Introduktion

At skrive enhedstests er noget, både begyndere og erfarne ingeniører typisk udskyder til senere udviklingsfaser, men alligevel – de er nøglen til stabil og robust softwareudvikling.

Den grundlæggende forudsætning for testdrevet udvikling (TDD) skriver dine tests, selv før du begynder at kode. Det er et fantastisk mål at stræbe efter, men det kræver en masse disciplin og planlægning, når du prøver at følge dens principper! For at gøre hele denne proces meget lettere, kan du ty til brugervenlige og kraftfulde test- og påstandsrammer, som f.eks. mokka , Chai.

I denne artikel vil vi starte med at introducere dig til disse to biblioteker og derefter vise dig, hvordan du bruger dem sammen til hurtigt at skabe læsbare og funktionelle enhedstests.

Chai

Chai er et påstandsbibliotek, der giver både BDD (adfærdsdrevet udvikling) , TDD (testdrevet udvikling) programmeringsstile til testkode og er beregnet til at blive parret med et testbibliotek, der lader dig organisere tests. Det er meget almindeligt parret med Mokka.

Det har tre hoved-API'er:

  • should
  • expect
  • assert

var.should.equal(var2)


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


assert.equal(var1, var2)

Igennem denne artikel vil vi fokusere på BDD-stilen ved hjælp af Chai's expect grænseflade, selvom det er helt okay at bruge andre grænseflader/stile efter din egen intuition. Det assert interface er de mest ens almindelige TDD assertion frameworks.

expect bruger et meget naturligt sprog API til at skrive dine påstande, hvilket vil gøre dine test nemmere at skrive og forbedre senere hen ad vejen. Dette gøres ved at kæde getters sammen for at skabe og udføre påstanden, hvilket gør det nemmere at oversætte krav til kode:

let user = {name: 'Scott'};


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

Bemærk: Se, hvordan du stort set kan læse påstanden i et naturligt sprog og forstå, hvad der foregår? Det er en af ​​de vigtigste fordele ved at bruge et påstandsbibliotek som Chai!

Et par flere eksempler på disse gettere er:

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

En hel del af disse gettere kan kædes sammen og bruges med påstandsmetoder som true, ok, existog empty for at skabe nogle komplekse påstande på kun én linje:

"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);

Bemærk: En komplet liste over de tilgængelige metoder kan findes link..

Du vil måske også tjekke listen over tilgængelige Plugins for Chai. Disse gør det meget nemmere at teste mere komplekse funktioner.

Tag chai-http for eksempel, som er et plugin, der hjælper dig med at teste serverruter:

"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);
    });

Organisering af testcases med Mokka – beskriv() og det()

Mocha er en testramme for Node, der giver dig fleksibiliteten til at køre asynkron (eller synkron) kode serielt. Eventuelle ufangede undtagelser vises sammen med testcasen, hvor den blev kastet, hvilket gør det nemt at identificere præcis, hvad der fejlede og hvorfor.

Det anbefales at installere Mocha globalt:

$ npm install mocha -g

Du vil have, at det skal være en global installation siden mocha kommandoen bruges til at køre testene for projektet i din lokale mappe.

Hvad gør dette stykke kode?

it() skal returnere X. it() definerer testcases, og Mocha vil køre hver it() som en enhedstest. For at organisere flere enhedstests kan vi describe() en fælles funktionalitet, og dermed strukturere Mokka-tests.

Dette er nok bedst beskrevet med et konkret eksempel:

"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);
        });
    });
});

I describe() metode, definerede vi en test navn, Kaldet #abs(). Du kan også køre test individuelt efter deres navn – dette vil blive dækket senere.

Bemærk: Med Mokka-tests behøver du det ikke require() nogen af ​​Mokka-metoderne. Disse metoder leveres globalt, når de køres med mocha kommando.

For at køre disse test skal du gemme din fil og bruge mocha kommando:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given number 


  1 passing (9ms)

Outputtet er en opdeling af de test, der kørte, og deres resultater. Læg mærke til, hvordan den indlejrede describe() opkald overføres til resultaterne. Det er nyttigt at have alle testene for en given metode eller funktion indlejret sammen.

Disse metoder er grundlaget for Mokka-testrammerne. Brug dem til at sammensætte og organisere dine tests, som du vil. Vi vil se et eksempel på dette i næste afsnit.

Skrive tests med Mokka og Chai

Den anbefalede måde at organisere dine tests på i dit projekt er at lægge dem alle sammen /test vejviser. Som standard kontrollerer Mocha for enhedstest ved hjælp af globs ./test/*.js , ./test/*.coffee. Derfra vil den indlæse og udføre enhver fil, der kalder describe() fremgangsmåde.

Tjek vores praktiske, praktiske guide til at lære Git, med bedste praksis, brancheaccepterede standarder og inkluderet snydeark. Stop med at google Git-kommandoer og faktisk lærer det!

Det er almindeligt at suffikse testfilerne med .test.js for kildefilerne, der indeholder Mokka-tests:

├── package.json
├── lib
│   ├── db.js
│   ├── models.js
│   └── util.js
└── test
    ├── db.test.js
    ├── models.test.js
    ├── util.test.js
    └── util.js

util.js i test bibliotek ville ikke indeholde nogen enhedstest, kun hjælpefunktioner til at hjælpe med test.

Bemærk: Du kan bruge den struktur, der giver mening for dig, enhedstestene bliver automatisk opfanget.

Når det kommer til rent faktisk at skrive testene, hjælper det at organisere dem ved hjælp af describe() metoder. Du kan organisere dem efter funktion, funktion, fil eller et hvilket som helst andet vilkårligt niveau. For eksempel ser en testfil organiseret til at beskrive arbejdet på funktionsniveau sådan her:

"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);
        });
    });
});

Kørsel af testene vil så give dig outputtet:

$ 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)

Hvis du udvider endnu mere, har du måske endda test for flere metoder i en enkelt fil. I dette tilfælde er metoderne grupperet efter Math objekt:

"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);
        });
    });
});

Hvilket resulterer i:

$ 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)

Mokkakroge – før(), efter(), førHver() og efterHver()

Ganske vist er de fleste enhedstests ikke så enkle. Mange gange har du sikkert brug for andre ressourcer til at udføre dine tests, såsom en database eller en anden ekstern ressource (eller en mock/stump af dem). For at sætte dette op, kan vi bruge et eller flere af følgende Mokka krog metoder:

  • before(): Kører før alle test i den givne blok
  • beforeEach(): Kører før hver test i den givne blok
  • after(): Kører efter alle test i den givne blok
  • afterEach(): Kører efter hver test i den givne blok

Disse kroge er det perfekte sted til at udføre opsætnings- og nedtagningsarbejde, der kræves til dine tests. Et af de almindelige brugstilfælde er at etablere en forbindelse til din database, før du kører testene:

"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) {
            
        });
    });
});

Før enhver af testene køres, sendes funktionen til vores before() metoden køres (og kun køres én gang gennem testene), hvilket etablerer en forbindelse til databasen. Når dette er gjort, køres vores testpakker.

Da vi ikke ønsker, at dataene fra en testsuite skal påvirke vores andre test, skal vi rydde dataene fra vores database, efter at hver suite er kørt. Det er hvad afterEach() er for. Vi bruger denne krog til at rydde alle databasedata efter hver testcase køres, så vi kan starte fra en ren tavle til de næste tests.

Kører Mokka-tests

I de fleste tilfælde er denne del ret enkel. Forudsat at du allerede har installeret Mocha og navigeret til projektbiblioteket, skal de fleste projekter blot bruge mocha kommando uden argumenter til at køre deres test:

$ 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)

Dette er lidt anderledes end vores tidligere eksempler, da vi ikke behøvede at fortælle Mocha, hvor vores test var placeret. I dette eksempel er testkoden på den forventede placering af /test.

Der er dog nogle nyttige muligheder, du måske vil bruge, når du kører tests. Hvis nogle af dine tests fejler, for eksempel, vil du sandsynligvis ikke køre hele suiten, hver gang du foretager en ændring. For nogle projekter kan den fulde testpakke tage et par minutter at fuldføre. Det er meget spildtid, hvis du virkelig kun skal køre én test.

I tilfælde som dette bør du fortæl Mocha, hvilke test der skal køres. Dette kan gøres ved hjælp af -g or -f valgmuligheder.

For at køre individuelle tests kan du levere -g flag og tilføj et fælles mønster mellem de test, du vil køre. For eksempel, hvis du ønsker at køre #sqrt() test:

$ 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)

Bemærk at #abs() test var ikke inkluderet i denne kørsel. Hvis du planlægger i overensstemmelse hermed med dine testnavne, kan denne mulighed bruges til kun at køre specifikke sektioner af dine tests.

Dette er dog ikke de eneste nyttige muligheder. Her er et par flere muligheder for Mokka, som du måske vil tjekke ud:

  • --invert: Inverterer -g , -f tændstikker
  • --recursive: Inkluder undermapper
  • --harmony: Aktiver alle harmonifunktioner i Node

Bemærk: Du kan se den fulde liste over muligheder ved at bruge mocha -h kommando eller tændt denne side.

Hvor kan man lære mere? Der er langt mere til dette emne, end vi kan dække i en kort artikel, så hvis du vil vide mere, vil vi anbefale at tjekke den officielle mokka , Chai dokumentation.

Konklusion

Husk, at både Mocha og Chai kan bruges til at teste stort set enhver type Node-projekt, uanset om det er et bibliotek, kommandolinjeværktøj eller endda et websted. Ved at bruge de forskellige muligheder og plugins, der er tilgængelige for dig, burde du være i stand til at tilfredsstille dine testbehov temmelig nemt. Hvert af disse biblioteker er meget nyttigt til at validere din kode og bør bruges i stort set alle dine Node-projekter.

Forhåbentlig har dette tjent som en nyttig introduktion til Mocha og Chai. Der er meget mere at lære end det, jeg har præsenteret her, så sørg for at tjekke dokumenterne for mere information.

Tidsstempel:

Mere fra Stablemisbrug