Mocha beforeEach vs 执行前
Posted
技术标签:
【中文标题】Mocha beforeEach vs 执行前【英文标题】:Mocha beforeEach vs before execution 【发布时间】:2015-12-16 02:07:17 【问题描述】:我最近遇到了一个我无法解释的问题。我在这些测试中有很多代码,所以我将尽我所能在这里捕捉到这个想法
我的测试看起来像:
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
);
);
);
问题是,#1
的 beforeEach 运行良好。我可以看到它发生在数据库上,#2
中的测试通过了。
但是,#4
的首选项上下文中的测试失败,因为它无法找到在#3
登录的用户。
似乎上下文before
在描述beforeEach
之前执行,这导致它们失败。如果我将logUserIn
移动到it
块中,它可以正常工作。
这是什么原因造成的?
【问题讨论】:
无法解释为什么“似乎之前的上下文是在 describe beforeEach 之前执行的”,但你不应该在某个时候执行done
以前?
Before 是在整个块之前,beforeEach 是在每个测试之前。
@StevenScott 所以这就是为什么。 describe beforeEach 在之前的上下文之后运行。我希望文档让这一点更明显
【参考方案1】:
虽然此答案只是再次显示文档说明,并且有一些 cmets 试图帮助显示差异,但应参考以下@tomasz-wszelaki 的答案。
Mocha 的测试运行器在Hooks section of the Mocha Test Runner 中对这个功能的解释最好。
来自 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
);
您可以将这些例程嵌套在其他也可以具有 before/beforeEach 例程的描述块中。
【讨论】:
恕我直言,文档并没有很好地解释这种行为,正如关于这个特定主题的大量问题所证明的那样。 @tomasz-wszelaki 的回答比逐字引用文档更有启发性。 @Aea 感谢您的评论。我阅读了另一个答案,并且这个例子看起来更清楚,所以我已经更新了我的 cmets 关于这个问题。在复制样本时,我没有考虑 Tomasz 所做的结构。【参考方案2】:我发现了一个类似的问题。该文档具有误导性,因为“在此块之前”意味着(至少对我而言)“在此描述部分之前”。同时它的意思是“在任何描述部分之前”。检查这个例子:
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
您将before
放在层次结构中的哪个位置似乎无关紧要 - 它会在任何描述之前运行,而不是在其包含的描述之前运行。
【讨论】:
把它想象成“在每个块之前”。这意味着在每次测试之前和每次描述之前。 感谢您的澄清!帽子是我问自己的问题,因为我在我们的项目中看到 before() 钩子在嵌套的 describe() 中定义,所以人们认为它是在描述上下文的关系中运行的,但事实并非如此。 Mocha 文档在这件事上可能更精确,充其量,除了最上面的 describe() 之外,其他任何地方都不应该允许它。 感谢您的解释。我很震惊地发现 Mocha 发现这个实现之前更多的是一个功能而不是一个错误。为什么它不尊重块(描述/上下文)范围?!【参考方案3】:混淆的原因在于 mocha 的文档。 你可以在mocha找到:
测试可以出现在你的钩子之前、之后或穿插在你的钩子中。 Hooks 将按照它们定义的顺序运行,视情况而定;所有 before() 钩子运行(一次),然后是任何 beforeEach() 钩子、测试、任何 afterEach() 钩子,最后是 after() 钩子(一次)。
讨论的钩子 before
和 beforeEach
分别在所有或每个 it
之前执行 - 在 describe 部分之前无法执行它。
在这里,您可以 find 对 mocha 主分支的 #1 贡献者的回答添加类似 beforeDescribe
钩子的内容。
我认为你应该看看--delay
mocha option。
【讨论】:
【参考方案4】:关键是要有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.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);
);
);
);
【讨论】:
以上是关于Mocha beforeEach vs 执行前的主要内容,如果未能解决你的问题,请参考以下文章
`before()` 和 `beforeEach()` 有啥区别?