Sök…


Grundläggande påstående

På sin mest grundläggande nivå ger enhetstestning på alla språk påståenden mot någon känd eller förväntad produktion.

function assert( outcome, description ) { 
    var passFail = outcome ? 'pass' : 'fail'; 
    console.log(passFail, ': ', description);
    return outcome;
};

Den populära påståendemetoden ovan visar oss ett snabbt och enkelt sätt att hävda ett värde i de flesta webbläsare och tolkar som Node.js med praktiskt taget vilken version av ECMAScript som helst.

Ett bra enhetstest är utformat för att testa en diskret enhet. vanligtvis en funktion.

function add(num1, num2) { 
    return num1 + num2; 
} 
 
var result = add(5, 20); 
assert( result == 24, 'add(5, 20) should return 25...'); 

I exemplet ovan är returvärdet från funktionen add(x, y) eller 5 + 20 tydligt 25 , så vår påstående om 24 bör misslyckas och påståttmetoden loggar en "fail" -rad.

Om vi helt enkelt modifierar vårt förväntade uttalande, kommer testet att lyckas och den resulterande produktionen ser ut så här.

assert( result == 25, 'add(5, 20) should return 25...');

console output:

> pass: should return 25...

Denna enkla påstående kan säkerställa att i många olika fall kommer din "add" -funktion alltid att returnera det förväntade resultatet och kräver inga ytterligare ramverk eller bibliotek för att fungera.

En strängare uppsättning påståenden skulle se ut så här (med var result = add(x,y) för varje påstående):

assert( result == 0, 'add(0, 0) should return 0...');
assert( result == -1, 'add(0, -1) should return -1...');
assert( result == 1, 'add(0, 1) should return 1...');

Och konsolutgång skulle vara detta:

> pass: should return 0...
> pass: should return -1...
> pass: should return 1...

Vi kan nu säkert säga att add(x,y) ... ska returnera summan av två heltal . Vi kan rulla upp dem till något liknande:

function test__addsIntegers() {

    // expect a number of passed assertions
    var passed = 3;

    // number of assertions to be reduced and added as Booleans
    var assertions = [

        assert( add(0, 0) == 0, 'add(0, 0) should return 0...'),
        assert( add(0, -1) == -1, 'add(0, -1) should return -1...'),
        assert( add(0, 1) == 1, 'add(0, 1) should return 1...')

    ].reduce(function(previousValue, currentValue){

        return previousValue + current;

    });

    if (assertions === passed) {

        console.log("add(x,y)... did return the sum of two integers");
        return true;

    } else {

        console.log("add(x,y)... does not reliably return the sum of two integers");
        return false;

    }
}

Enhetstestlöften med Mocha, Sinon, Chai och Proxyquire

Här har vi en enkel klass som ska testas som ger ett Promise baserat på resultaten från en extern ResponseProcessor som tar tid att köra.

För enkelhets skull antar vi att processResponse metoden aldrig kommer att misslyckas.

import {processResponse} from '../utils/response_processor';

const ping = () => {
  return new Promise((resolve, _reject) => {
    const response = processResponse(data);
    resolve(response);
  });
}

module.exports = ping;

För att testa detta kan vi utnyttja följande verktyg.

  1. mocha
  2. chai
  3. sinon
  4. proxyquire
  5. chai-as-promised

Jag använder följande test skript i min package.json fil.

"test": "NODE_ENV=test mocha --compilers js:babel-core/register --require ./test/unit/test_helper.js  --recursive test/**/*_spec.js"

Detta tillåter mig att använda es6 syntax. Den refererar till en test_helper som kommer att se ut

import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import chaiAsPromised from 'chai-as-promised';
import sinonStubPromise from 'sinon-stub-promise';

chai.use(sinonChai);
chai.use(chaiAsPromised);
sinonStubPromise(sinon);

Proxyquire tillåter oss att injicera vår egen stubbe på platsen för den externa ResponseProcessor . Vi kan sedan använda sinon att spionera på den stubbens metoder. Vi använder tillägget för att chai att chai-as-promised injicerar för att kontrollera att ping() -metodens löfte är fullfilled , och att det eventually returnerar det nödvändiga svaret.

import {expect}       from 'chai';
import sinon          from 'sinon';
import proxyquire     from 'proxyquire';

let formattingStub = {
  wrapResponse: () => {}
}

let ping = proxyquire('../../../src/api/ping', {
  '../utils/formatting': formattingStub
});

describe('ping', () => {
  let wrapResponseSpy, pingResult;
  const response = 'some response';

  beforeEach(() => {
    wrapResponseSpy = sinon.stub(formattingStub, 'wrapResponse').returns(response);
    pingResult = ping();
  })

  afterEach(() => {
    formattingStub.wrapResponse.restore();
  })

  it('returns a fullfilled promise', () => {
    expect(pingResult).to.be.fulfilled;
  })

  it('eventually returns the correct response', () => {
    expect(pingResult).to.eventually.equal(response);
  })
});

Låt oss istället anta att du vill testa något som använder svaret från ping .

import {ping} from './ping';

const pingWrapper = () => {
  ping.then((response) => {
    // do something with the response
  });
}

module.exports = pingWrapper;

För att testa pingWrapper utnyttjar vi

  1. sinon
  2. proxyquire
  3. sinon-stub-promise

Som tidigare tillåter Proxyquire oss att injicera vår egen stubbe på platsen för det yttre beroendet, i detta fall ping som vi testade tidigare. Vi kan sedan använda sinon att spionera på den stubbens metoder och utnyttja sinon-stub-promise att tillåta oss att returnsPromise . Detta löfte kan sedan lösas eller avvisas som vi vill i testet, för att testa omslagets svar på det.

import {expect}   from 'chai';
import sinon      from 'sinon';
import proxyquire from 'proxyquire';

let pingStub = {
  ping: () => {}
};

let pingWrapper = proxyquire('../src/pingWrapper', {
  './ping': pingStub
});

describe('pingWrapper', () => {
  let pingSpy;
  const response = 'some response';

  beforeEach(() => {
    pingSpy = sinon.stub(pingStub, 'ping').returnsPromise();
    pingSpy.resolves(response);
    pingWrapper();
  });

  afterEach(() => {
    pingStub.wrapResponse.restore();
  });

  it('wraps the ping', () => {
    expect(pingSpy).to.have.been.calledWith(response);
  });
});


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow