NodeJS Mocha beforeEach与before execution

rjee0c15  于 2023-04-29  发布在  Node.js
关注(0)|答案(4)|浏览(95)

我最近遇到了一个我无法解释的问题。我在这些测试中有很多代码,所以我将尽我最大的努力来捕捉这里的想法
我的测试看起来像:

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

问题是,beforeEach by #1运行正常。我可以看到它发生在DB上,#2中的测试通过了。
但是,#4上的首选项上下文中的测试失败,因为它找不到用户在#3上登录。
看起来上下文before在describe beforeEach之前执行,这导致它们失败。如果我将logUserIn移动到it块中,它就可以正常工作。
什么会导致这种情况?

wfveoks0

wfveoks01#

虽然这个答案只是再次显示了文档注解,并有一些评论试图帮助显示差异,但应该参考@tomasz-wszelaki下面的答案。
Mocha的测试运行器在Mocha测试运行器的钩子部分最好地解释了这个功能。
从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
});

您可以将这些例程嵌套在其他describe块中,这些describe块也可以具有before/beforeEach例程。

1l5u6lss

1l5u6lss2#

我发现了类似的问题。文档是误导性的,因为“在此块之前”意味着(至少对我来说)“在此描述部分之前”。同时,它表示“在任何描述部分之前”。检查以下示例:

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

输出顺序:

    • 内部描述1 -之前 *
    • 外部描述- beforeEach*
    • 内部描述2 - beforeEach*

似乎将before放在层次结构中的哪个位置并不重要-它将在任何describe之前运行,而不是在其包含的describe之前运行。

d7v8vwbk

d7v8vwbk3#

混淆的原因在于摩卡的文档。你可以在Mocha中找到:
测试可以出现在钩子之前、之后或穿插在钩子中。钩子将按照定义的顺序运行;所有before()钩子运行(一次),然后是任何beforeEach()钩子、测试、任何afterEach()钩子,最后是after()钩子(一次)。
讨论的钩子beforebeforeEach分别在所有或每个it之前执行-没有办法在describe部分之前执行它。
在这里,你可以找到mocha的master分支的#1贡献者的答案,添加类似beforeDescribe钩子的东西。
我想你应该看看--delay摩卡选项。

rpppsulh

rpppsulh4#

关键是要有一个mocha.opts文件,它的线指向./test/bootstrap.js,在那里你应用before,beforeAll,after,afterAll钩子。

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调试标志
/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。选择

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

相关问题