unendo test da più file con mocha.js


87

Sto cercando di unire tutti i test da più file in un unico file, qualcosa del genere:

  describe('Controllers', function() {
    describe('messages.js', function() {
      require('./controllertests/messages').test(options);
    })
    describe('users.js', function() {
      require('./controllertests/users').test(options);
    })
  })

Sono abbastanza sicuro che questo non sia il modo migliore per partecipare ai test, ho qualche difficoltà a trovare esempi su come farlo: s


1
Curioso, perché i test devono essere riuniti in un unico file?
thgaskell

2
Per condividere variabili locali e organizzazione
coiso

Potrebbe avere più senso se includi i test nella domanda. Sembra che tu possa essere incline ai test di integrazione (al contrario degli unit test). In genere non dovresti aver bisogno di condividere le variabili tra i test.
thgaskell

2
E il grosso problema è che preferirei avere 20 file piuttosto che 1 file
enorme

2
Inoltre, se si guarda a come Mocha gestisce le suite con il concetto di .only()esso potrebbe essere utile poter mettere describe.only()in esecuzione ancora un'intera directory di test. Questo è ciò che mi ha portato qui.
Chris

Risposte:


113

Se vuoi includere più moduli nella tua describegerarchia come stai facendo nella tua domanda, quello che stai facendo è praticamente quello , a meno che tu non voglia scrivere un caricatore di test personalizzato per Mocha. Scrivere il caricatore personalizzato non sarebbe più facile o rendere il tuo codice più chiaro di quello che hai già.

Ecco un esempio di come cambierei alcune cose. La testsottodirectory in questo esempio è organizzata come:

.
└── test
    ├── a
    │   └── a.js
    ├── b
    │   └── b.js
    ├── common.js
    └── top.js

top.js:

function importTest(name, path) {
    describe(name, function () {
        require(path);
    });
}

var common = require("./common");

describe("top", function () {
    beforeEach(function () {
       console.log("running something before each test");
    });
    importTest("a", './a/a');
    importTest("b", './b/b');
    after(function () {
        console.log("after all tests");
    });
});

La importTestfunzione è solo per mostrare come sarebbe possibile gestire la ripetizione di importare più moduli senza dover ridigitare il tutto describe(... require...ogni volta. Il commonmodulo ha lo scopo di contenere ciò che è necessario utilizzare in più moduli della suite di test. In realtà non lo sto usando topma potrebbe essere usato lì, se necessario.

Noterò qui che beforeEacheseguirà il suo codice prima di ogni singolo test registrato, itindipendentemente dal fatto che appaia all'interno di describein topo in uno qualsiasi dei moduli importati . Con --recursive, il beforeEachcodice dovrebbe essere copiato in ogni modulo o forse avresti un beforeEachhook in ogni modulo che chiama una funzione importata da un modulo comune.

Inoltre, l' afterhook verrà eseguito dopo tutti i test nella suite. Questo non può essere replicato con --recursive. Se si utilizza --recursivee si aggiunge il codice di aftera ciascun modulo, verrà eseguito una volta per modulo anziché solo una volta per l' intero test.

La visualizzazione di tutti i test sotto una singola topintestazione non può essere replicata utilizzando --recursive. Con --recursiveogni file potrebbe essere describe("top"ma questo creerebbe una nuova topintestazione per ogni file.

common.js:

var chai = require("chai");

var options = {
    foo: "foo"
};

exports.options = options;
exports.chai = chai;
exports.assert = chai.assert;

L'utilizzo di un modulo chiamato in commonquesto modo è qualcosa che ho fatto in alcune delle mie suite di test per evitare di dover fare requireun mucchio di cose più e più volte e per mantenere variabili o funzioni globali di sola lettura che non mantengono lo stato. Preferisco non inquinare l' globaloggetto come nella risposta di thgaskell perché questo oggetto è veramente globale e accessibile anche in librerie di terze parti che il tuo codice potrebbe caricare. Questo non è qualcosa che trovo accettabile nel mio codice.

a/a.js:

var common = require("../common");
var options = common.options;
var assert = common.assert;

it("blah a", function () {
    console.log(options.foo);
    assert.isTrue(false);
});

b/b.js:

it("blah b", function () {});

3
Sebbene sia d'accordo sul fatto che non si dovrebbe inquinare l' globalambito, lo uso per le librerie di asserzioni per mantenere più puliti i file di prova. Non è come se stessi sovrascrivendo global.process. Le variabili locali sovrascriveranno a globalmeno che altre librerie non lo chiamino esplicitamente, il global.XYZche è improbabile. Dura solo per la durata dei test. Non mi ha ancora fatto male, ma ti farò sapere nel momento in cui mi morde il culo :)
thgaskell

Qual è la differenza tra importTeste calling require('path')()for example?
CherryNerd

@CreasolDev La importTestfunzione è solo una funzione comoda. La cosa importante che fa è racchiudere la requirechiamata in un describeblocco. È importante che la requirechiamata venga racchiusa describealtrimenti i moduli non saranno isolati nel loro blocco e qualsiasi hook impostato dal file importato verrà impostato sul blocco sbagliato. Se importTestfosse stato sostituito con una chiamata diretta a requiresenza wrapping describe, i moduli a/ae b/bavrebbero condiviso gli hook. Ad esempio, un beforeEachhook impostato b/bverrà eseguito anche prima di ogni test in a/a.
Louis

1
NON eseguirò alcuna logica come prima di ogni descrizione del tuo livello superiore. Lascia che ogni file faccia il suo prima di ogni "roba". Se lo fai, accoppierai i tuoi test tra loro e l'implementazione non correlata.
PositiveGuy

1
Farei anche il wrapping delle descrizioni nei rispettivi file, non nella funzione importTest. Le descrizioni di livello superiore in ogni rispettivo file dovrebbero comunque descrivere lo scopo delle suite di test
PositiveGuy

35

Anche se questo potrebbe non essere direttamente collegato alla domanda, la risposta che stavo cercando era:

$ mocha --recursive

Eseguirà tutti i test nelle sottodirectory della cartella "test". Neat. Evita di dover mantenere un elenco di test che voglio caricare e in realtà eseguire sempre tutto.


3
Migliore risposta! Molto più semplice di altre soluzioni proposte.
caiosm1005

12
@ caiosm1005 Questa risposta non risolve effettivamente il problema presentato dall'OP . Certo, se non hai bisogno di fare quello che vuole l'OP , allora dovresti usarlo. Tuttavia, se vuoi racchiudere ogni file di prova in più describeblocchi, i describeblocchi che si estendono su file, --recursivenon lo faranno. Visto che non risolve il problema dell'OP, non lo definirei "migliore".
Louis

@louis - Credo che tu possa racchiudere ogni file separato in describeblocchi
Ian Jamieson

4
@IanJamieson L'OP sta cercando di avere più file coperti da un singolo describe blocco. Guarda la domanda. Il describeblocco "Controller" dovrebbe comprendere i test di ./controllertests/messages.jse ./controllertests/users.js. Schiaffeggiare --recursiveun'invocazione Mocha non crea magicamente un describe("Controllers"blocco.
Louis

3
@Louis Sto solo cercando di aiutare. Scusa se ti ho offeso cercando di creare magicamente describeblocchi, cosa che in realtà ho imparato a fare da Silente in persona.
Ian Jamieson

16

Non c'è nulla che ti impedisca di eseguire più file di test. In generale, ogni test non dovrebbe dipendere dai risultati di un altro test, quindi la condivisione delle variabili non è qualcosa che vorresti fare.

Ecco un esempio di come potresti organizzare i tuoi file di prova.

.
├── app.js
└── test
    ├── common.js
    ├── mocha.opts
    │
    ├── controllers
    │   ├── messages-controller.js
    │   └── users-controller.js
    │
    └── models
        ├── messages-model.js
        └── users-model.js

Quindi all'interno del tuo mocha.optsfile, assicurati di impostare l' --recursiveopzione.

mocha.opts

--ui bdd
--recursive

Se sono presenti moduli comuni che desideri includere in tutti i file, puoi aggiungerli al common.jsfile. I file nella radice della testdirectory verranno eseguiti prima dei file nelle directory nidificate.

common.js

global.chai = require('chai');
global.assert = chai.assert;
global.expect = chai.expect;
chai.should();
chai.config.includeStack = true;

process.env.NODE_ENV = 'test';

// Include common modules from your application that will be used among multiple test suites.
global.myModule = require('../app/myModule');

3
A qualcuno dispiacerebbe aggiungere codice per i file nelle directory dei controller e dei modelli? Sarebbe fantastico avere un esempio completo.
Gavin

@Gavin - queste saranno solo tute di prova in modo da conteneredescribe('mytest', function() { /* ..... etc */ });
Ian Jamieson

8

So che questo è un vecchio post ma volevo intervenire con quella che è stata una buona soluzione per me, molto simile al metodo proposto da OP.

Il progetto a cui sto lavorando è ben collaudato e i test continuano a crescere. Ho finito per usarlo requireperché è sincrono e quindi rende un po 'più facile comporre i tuoi test senza troppe modifiche all'architettura:

// inside test/index.js

describe('V1 ROUTES', () => {
  require('./controllers/claims.test');
  require('./controllers/claimDocuments.test');
  require('./controllers/claimPhotos.test');
  require('./controllers/inspections.test');
  require('./controllers/inspectionPhotos.test');
  require('./controllers/versions.test');
  require('./services/login.v1.test');
});

describe('V2 ROUTES', () => {
  require('./services/login.v2.test');
  require('./services/dec-image.v2.test');
});

describe('V3 ROUTES', () => {
  require('./services/login.v3.test');
  require('./services/getInspectionPhotosv3.test');
  require('./services/getPolicyInfo.v3.test');
});

describe('ACTIONS', () => {
  require('./actions/notifications.test');
});

2

Ho avuto un problema simile in cui avevo un sacco di test per classi nella stessa categoria e volevo raggrupparli insieme per renderli più facili da visualizzare in un IDE. Tutti i miei test e codice utilizzavano già moduli ES6: non volevo riscriverli tutti per usarli requirecome ho visto in altri esempi.

L'ho risolto facendo describeesportare il mio "raggruppamento" , quindi importandolo nei miei file di prova e aggiungendoli a livello di codice al file importato describe. Ho finito per creare un metodo di supporto per astrarre tutto l'impianto idraulico.

In someCategory.spec.js

const someCategory= describe("someCategory", () => {});


// Use this just like a regular `describe` to create a child of this scope in another file
export default function describeMember(skillName, testFn) {
  return describe(skillName, function configureContext() {
    // Make context a child of `someCategory` context
    function Context() {}
    Context.prototype = someCategory.ctx;
    this.ctx = new Context();
    // Re-parent the suite created by `describe` above (defaults to root scope of file it was created in)
    this.parent.suites.pop();
    someCategory.addSuite(this);
    // Invoke the fn now that we've properly set up the parent/context
    testFn.call(this);
  });
}

Nelle prove individuali:

import { default as describeCategoryMember } from './someCategory.spec';

describeCategoryMember('something', () => {
    describe('somethingElse', () => {
        ...
    });

    it('a test', () => {
        ...
    });
})

-11
describe( 'Running automation test, Please wait for all test to complete!'.red, function () {


    var run = require( './Test.js' );

    for ( var i = 0; i < 2; i++ ) {
        run.badLogin();
        run.loginLimited();
        run.acceptJob();
        run.drivingToJob();
        run.arrivedAtJob();
        run.towingJob();
        run.arrivedDestination();
        run.jobComplete();
        run.restrictionLicensePlate();
        run.newNodeMainMenu();
        run.newNodeMainMenuToDrafts();
        run.draftDelete();
        run.resetAllData();
        run.companyVehicle();
        run.actionsScreenClockInOut();
        run.mainMenuLogout();
        run.loginAdmin();
        run.actionsScreenLogout();
    }
} );

3
È meglio aggiungere una descrizione insieme al codice in modo che altri possano determinare se questa è una risposta accettabile.
Suever

2
Perché il loop? Cosa c'è dentro ./Test.js? Chissà? Per la cronaca, attualmente sono il miglior risponditore nel tag mocha . Conosco Mocha dentro e fuori ma non riesco a dare un senso a questa risposta.
Louis

@Louis sembra che volesse eseguire i test n volte utilizzando il ciclo.
Akash Agarwal
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.