it-swarm.com.de

Mokka vor jeder vs vor der Ausführung

Ich bin kürzlich auf ein Problem gestoßen, das ich nicht erklären kann. Ich habe eine Menge Code in diesen Tests, deshalb werde ich mein Bestes geben, um die Idee hier festzuhalten

Ich habe Tests, die so aussehen:

describe('main page', function(){
  beforeEach(function(done){
    addUserToMongoDb(done);   // #1
  });

  afterEach(function(done){
    removeUserFromMongoDb(done);
  });

  context('login', function(){
     it('should log the user in, function(){
       logUserIn(user_email);  // #2 - This line requires the user from the beforeEach
     });
  });

  context('preferences', function(){
    before(function(done){    //#3
       logUserInBeforeTest(user_email);
     });

    it('should show the preferences', function(){
       doCheckPreferences(); // #4
    });
  });
});

Das Problem ist, das beforeEach von #1 Läuft einwandfrei. Ich kann sehen, dass es in der DB passiert und die Tests in #2 Bestanden haben.

Die Tests im Einstellungskontext unter #4 Schlagen jedoch fehl, da der Benutzer nicht gefunden werden kann, um sich unter #3 Anzumelden.

Es scheint, dass der Kontext before vor dem Text beforeEach ausgeführt wird, wodurch sie fehlschlagen. Wenn ich logUserIn in den it -Block verschiebe, funktioniert es einwandfrei.

Was könnte das verursachen?

44
Tomo

Mochas Testrunner erklärt diese Funktionalität am besten im Hooks-Bereich des Mocha-Testrunners .

Aus dem Bereich Hooks:

describe('hooks', function() {

    before(function() {
        // runs before all tests in this file regardless where this line is defined.
    });

    after(function() {
        // runs after all tests in this file
    });

    beforeEach(function() {
        // runs before each test in this block
    });

    afterEach(function() {
        // runs after each test in this block
    });

    // test cases
});

Sie können diese Routinen in anderen Beschreibungsblöcken verschachteln, die auch Before/BeforeEach-Routinen enthalten können.

54
Steven Scott

Ich habe ein ähnliches Problem gefunden. Die Dokumentation ist irreführend, weil "vor diesem Block" (zumindest für mich) "vor diesem Beschreibungsabschnitt" bedeutet. Inzwischen bedeutet es "vor jedem Abschnitt beschreiben". Überprüfen Sie dieses Beispiel:

describe('outer describe', function () {
    beforeEach(function () {
        console.log('outer describe - beforeEach');
    });

    describe('inner describe 1', function () {
        before(function () {
            console.log('inner describe 1 - before');
        });

    describe('inner describe 2', function () {
        beforeEach(function () {
            console.log('inner describe 2 - beforeEach');
        });
 });

 // output will be:
 // inner describe 1 - before
 // outer describe - beforeEach
 // inner describe 2 - beforeEach

Es scheint, dass es egal ist, wo in Ihrer Hierarchie Sie das before setzen - es wird vor jedem beschreiben und nicht vor seinem enthaltenden beschreiben ausgeführt.

23
Tomasz Wszelaki

Der Grund der Verwirrung liegt in der Dokumentation von Mokka. Sie finden in Mokka :

Tests können vor, nach oder unterbrochen von Ihren Hooks angezeigt werden. Hooks werden in der Reihenfolge ausgeführt, in der sie definiert wurden. Alle before () -Hooks werden (einmal) ausgeführt, dann alle beforeEach () -Hooks, Tests, alle afterEach () -Hooks und schließlich after () -Hooks (einmal).

Besprochene Hooks before und beforeEach werden direkt vor allen oder jedem it ausgeführt - es gibt keine Möglichkeit, sie auszuführen, bevor describe Abschnitt.

Hier können Sie find die Antwort des ersten Mitwirkenden am Hauptzweig des Mokkas zu der Idee hinzufügen, etwas wie beforeDescribe hook.

Ich denke, Sie sollten sich die --delay Mokka Option .

10
Victor Perov

Das Wichtigste ist, eine mocha.opts - Datei mit der Zeile auf ./test/bootstrap.js Zu haben, in der Sie vor, vor und nach und nach allen Hooks anwenden.

Execute all tests:
 - npm test

Execute a single test:
- NODE_ENV=test node --inspect ./node_modules/.bin/_mocha --opts test/mocha.opts test/test/service/unSubscriber.test.js 

node --inspect Flag zum Debuggen


/package.json

{
  "name": "app",
  "version": "0.0.1",
  "engines": {
    "node": "11.9.0",
    "npm": "6.5.0"
  },
  "scripts": {
    "test": "NODE_ENV=test node --inspect ./node_modules/.bin/_mocha --opts test/mocha.opts test/**/**/**/*.js"
  },
  "private": true,
  "dependencies": {
    "express": "3.21.2",
    "mongoose": "^4.5.10",
    ...
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "faker": "^4.1.0",
    "mocha": "^6.0.0"
  }
}

/test/mocha.opts

--recursive
--timeout 30000
--reporter spec
--file ./test/bootstrap.js

/test/bootstrap.js

const mongoose = require('mongoose');
const config = require('./../service/config').getConfig();
mongoose.Promise = global.Promise;

before((done) => {
  (async () => {
    const connection = await mongoose.connect(config.mongo_url, { useMongoClient: true });
    await connection.db.dropDatabase();
  })().then(() => {
    require('../server');
    done();
  });
});

after((done) => {
  process.kill(process.pid, 'SIGTERM');
  done();
});

/server.js

const http = require('http');
const app = require('./app');
const config = require('./service/config');
const port = process.env.PORT || 4000;

const server = http.createServer(app);

server.listen(port, () => {
  console.log(`===== Server running:${config.getEnv()}=====`);
});

process.on('SIGTERM', () => {
  console.log('===== Server closed =====');
  process.exit(0);
});

/test/service/unSubscriber.test.js

const faker = require('faker');

const ContactOptOutRepository = require('../../repository/contactOptOut');
const UnSubscriber = require('../../service/unSubscriber');
const expect = require('chai').expect;

const contactOptOutRepository = new ContactOptOutRepository();
const unSubscriber = new UnSubscriber();

const emails = [
  faker.internet.email(),
  faker.internet.email(),
  faker.internet.email(),
  faker.internet.email(),
  faker.internet.email(),
];

describe('UnSubscriber', () => {
  it('should filter out unsubscribed emails', () => {
    return (async () => {
      await contactOptOutRepository.newUnSubscription(emails[0], faker.lorem.Word());
      await contactOptOutRepository.newUnSubscription(emails[1], faker.lorem.Word());
      await contactOptOutRepository.newUnSubscription(emails[2], faker.lorem.Word());

      return await unSubscriber.filterUnsubscribed(emails);
    })()
      .then(filtered => {
        expect(filtered.length).to.be.equal(2);
      });
  });
});


0