让 Mocha 在 运行 测试文件之前等待 index.js 完成加载
Make Mocha wait for index.js to finish loading before running test files
我有一个文件夹结构:
- app
- config
- config.js // environment variables
- express.js // creates an express server
- passwords
- passwords.controller.js
- passwords.route.js
- passwords.test.js
- index.js // main app file
我的索引文件异步加载应用程序:
function initMongoose() {
...
return mongoose.connect(config.mongo.host, {useNewUrlParser: true, keepAlive: 1})
.then((connection) => {
// Password is a function which connects the Password schema to the given connection
Password(connection);
})
.catch((e) => {
throw new Error(`Unable to connect to database: ${config.mongo.host}`);
});
}
async init() {
await initMongoose();
const app = require('./config/express');
const routes = require('./index.route');
app.use('/api', routes);
...
app.listen(3000, () => {
console.log('server started');
});
}
module.exports = init();
我的测试文件是这样构造的:
// Load the app async first then continue with the tests
require('../index').then((app) => {
after((done) => {
mongoose.models = {};
mongoose.modelSchemas = {};
mongoose.connection.close();
done();
});
describe('## Passwords API', () => {
...
});
});
我正在这样开始测试:
"test": "cross-env NODE_ENV=test ./node_modules/.bin/mocha --ui bdd --reporter spec --colors server --recursive --full-trace"
这就是怪异让我变得更好的地方。基本上它在 anything 之前加载 passwords.controller.js
else,这是因为 --recursive
选项。这不应该发生,因为 index.js
需要首先加载,以便它可以在任何测试 运行 之前连接到 mongoose 等,如果没有,那么来自 passwords.controller.js
的这个片段将抛出 MissingSchemaError: Schema hasn't been registered for model "Password".
因为模型 Password
此时尚未设置:
const Password = mongoose.connection.model('Password');
所以我尝试在 --recursive
选项之前添加 --require ./index.js
,这确实在 passwords.controller.js
之前加载了其他文件,但后者仍然在 index.js
之前 运行s甚至完成了。
解决方案 here 不起作用,因为 index.js
没有先 运行。
如何修改我的 test
脚本以允许我的 index.js
在我 运行 任何测试文件之前完成?
从技术上讲,您可以 运行 您的 index.js 文件,而不是通过 npm 测试(CLI)使用 mocha,您实际上可以 运行 在 index.js 之后以编程方式使用 mocha 进行测试. Mocha Programmatically example
import Mocha from 'mocha';
import fs from 'fs';
import path from 'path';
// Instantiate a Mocha instance.
const mocha = new Mocha();
const testDir = 'some/dir/test'
// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file) {
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file) {
mocha.addFile(
path.join(testDir, file)
);
});
// Run the tests.
mocha.run(function(failures) {
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
describe('## Passwords API', function() {
let appInstance;
before((done) => {
require('index.js').then((app) => {
appInstance = app
done();
});
});
});
参考:https://mochajs.org/#asynchronous-hooks
另一种可能的模式是有一个特殊的帮助文件。这就像一个单身人士或某种缓存。这允许服务器仅 bootstrap 一次,并为所有测试共享。请注意,这可能会在您的单元测试中导致不需要的 side-effects,但可以加快不影响应用程序对象的测试。
比如testUtil.js
let app = null;
async function getApp(){
if(app){
return app;
}
app = await require('index.js')
return app
}
module.export = {
getApp,
}
并在您的测试文件中
const helper = require('[your path]/testUtil.js')
describe('## Passwords API', function() {
let appInstance;
before((done) => {
helper.getApp().then((app) => {
appInstance = app
done();
});
});
});
我还建议将所有测试放在一个单独的文件夹中(可能称为 "tests")。这将确保 --recursive
仅加载测试。另一个好处是在生产中你可以跳过这个文件夹
我有一个文件夹结构:
- app
- config
- config.js // environment variables
- express.js // creates an express server
- passwords
- passwords.controller.js
- passwords.route.js
- passwords.test.js
- index.js // main app file
我的索引文件异步加载应用程序:
function initMongoose() {
...
return mongoose.connect(config.mongo.host, {useNewUrlParser: true, keepAlive: 1})
.then((connection) => {
// Password is a function which connects the Password schema to the given connection
Password(connection);
})
.catch((e) => {
throw new Error(`Unable to connect to database: ${config.mongo.host}`);
});
}
async init() {
await initMongoose();
const app = require('./config/express');
const routes = require('./index.route');
app.use('/api', routes);
...
app.listen(3000, () => {
console.log('server started');
});
}
module.exports = init();
我的测试文件是这样构造的:
// Load the app async first then continue with the tests
require('../index').then((app) => {
after((done) => {
mongoose.models = {};
mongoose.modelSchemas = {};
mongoose.connection.close();
done();
});
describe('## Passwords API', () => {
...
});
});
我正在这样开始测试:
"test": "cross-env NODE_ENV=test ./node_modules/.bin/mocha --ui bdd --reporter spec --colors server --recursive --full-trace"
这就是怪异让我变得更好的地方。基本上它在 anything 之前加载 passwords.controller.js
else,这是因为 --recursive
选项。这不应该发生,因为 index.js
需要首先加载,以便它可以在任何测试 运行 之前连接到 mongoose 等,如果没有,那么来自 passwords.controller.js
的这个片段将抛出 MissingSchemaError: Schema hasn't been registered for model "Password".
因为模型 Password
此时尚未设置:
const Password = mongoose.connection.model('Password');
所以我尝试在 --recursive
选项之前添加 --require ./index.js
,这确实在 passwords.controller.js
之前加载了其他文件,但后者仍然在 index.js
之前 运行s甚至完成了。
解决方案 here 不起作用,因为 index.js
没有先 运行。
如何修改我的 test
脚本以允许我的 index.js
在我 运行 任何测试文件之前完成?
从技术上讲,您可以 运行 您的 index.js 文件,而不是通过 npm 测试(CLI)使用 mocha,您实际上可以 运行 在 index.js 之后以编程方式使用 mocha 进行测试. Mocha Programmatically example
import Mocha from 'mocha';
import fs from 'fs';
import path from 'path';
// Instantiate a Mocha instance.
const mocha = new Mocha();
const testDir = 'some/dir/test'
// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file) {
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file) {
mocha.addFile(
path.join(testDir, file)
);
});
// Run the tests.
mocha.run(function(failures) {
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
describe('## Passwords API', function() {
let appInstance;
before((done) => {
require('index.js').then((app) => {
appInstance = app
done();
});
});
});
参考:https://mochajs.org/#asynchronous-hooks
另一种可能的模式是有一个特殊的帮助文件。这就像一个单身人士或某种缓存。这允许服务器仅 bootstrap 一次,并为所有测试共享。请注意,这可能会在您的单元测试中导致不需要的 side-effects,但可以加快不影响应用程序对象的测试。
比如testUtil.js
let app = null;
async function getApp(){
if(app){
return app;
}
app = await require('index.js')
return app
}
module.export = {
getApp,
}
并在您的测试文件中
const helper = require('[your path]/testUtil.js')
describe('## Passwords API', function() {
let appInstance;
before((done) => {
helper.getApp().then((app) => {
appInstance = app
done();
});
});
});
我还建议将所有测试放在一个单独的文件夹中(可能称为 "tests")。这将确保 --recursive
仅加载测试。另一个好处是在生产中你可以跳过这个文件夹