最近、説明できない問題に遭遇しました。これらのテストにはたくさんのコードがあるので、ここでアイデアをキャプチャするために最善を尽くします
次のようなテストがあります。
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が正常に実行されることです。 DBで発生していることと、#2
パスのテストを確認できます。
ただし、#4
でログインするユーザーを見つけることができないため、#3
の設定コンテキストでのテストは失敗します。
コンテキストbefore
は、describe beforeEach
の前に実行され、失敗するようです。 logUserIn
をit
ブロックに移動すると、正常に機能します。
何がこれを引き起こす可能性がありますか?
Mochaのテストランナーは、この機能を Mochaテストランナーのフックセクション で最もよく説明しています。
フックセクションから:
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ルーチンを持つことのできる他の記述ブロック内にネストできます。
同様の問題が見つかりました。 「このブロックの前」とは(少なくとも私にとって)「この記述セクションの前」を意味するため、ドキュメントは誤解を招くものです。一方、「記述セクションの前」を意味します。この例を確認してください:
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
を配置しても問題ないようです。describeを含む前ではなく、describeの前に実行されます。
混乱の原因は、モカのドキュメントにあります。 mocha で見つけることができます:
テストは、フックの前、後、または間に散らばって表示できます。フックは、必要に応じて定義された順序で実行されます。すべてのbefore()フックが実行され(1回)、beforeEach()フック、テスト、afterEach()フック、最後にafter()フックが1回実行されます。
議論されたフックbefore
とbeforeEach
は、それぞれすべてまたは各it
の直前に実行されます-前に実行する方法はありませんdescribeセクション。
ここで find アイデアへのモカのマスターブランチへの#1貢献者の回答は、beforeDescribe
フックのようなものを追加できます。
--delay
mocha option を見るべきだと思います。
重要なことは、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);
});
});
});