我正在创建一个mocha测试套件,该套件正在测试nwjs应用程序正在调用的命令行实用程序,该实用程序接收文件并生成输出json文件。我有成千上万个输入文件的组合,我要生成的测试(it()s)取决于cmdline实用程序的json输出内容。
Mocha似乎想要求我先创建所有it(),但这意味着这些脚本需要先运行并捕获json输出。我希望这样做:
'use strict';
const path = require('path');
const glob = require('glob');
const expect = require('sharedjs/chai-wrapper').expect;
const utils = require('sharedjs/utils');
describe('Generated Tests:', function() {
let testNum = 0;
let globOpts = { nodir: true }
let type1files = glob.sync(path.join(filetype1_dir, '*'), globOpts);
let type2files = glob.sync(path.join(filetype2_dir, '*'), globOpts);
for (let i = 0; i < type1files.length; i++) {
for (let j = 0; j < type2files.length; j++) {
testNum++;
let testName = utils.mkTestName(testNum, i, j);
describe(testName, function() {
let run;
before(function() {
run = utils.runCommand(type1files[i], type2files[j]);
// run = { status: result.status, command: result.args.join(' '), output: fse.readJsonSync(outfile) }
if (run.status !== 0) {
throw new Error(run.status+'='+run.command);
}
});
for (let key in run.output.analysis) {
it(key+'=0', function() {
expect(run.output.analysis[key].value).to.be.equal('0', key+'=0');
}
}
});
}
}
});
我将在这里进行数千个命令行调用。我不想让它们全都放在前面,缓存文件(或更糟糕的是,将所有json对象加载到内存中)然后开始运行测试。
我知道我可以创建一个高级“ validate json”测试,然后在其中执行一堆Expect(),但是这样做有两个问题。首先,它们不会是显示为失败的独立命名测试,其次,第一个期望失败将使测试失败,因此我无法再深入json范围内查看其他错误。
想法?
-使用utils.runCommand()的示例JSON输出进行更新-
{
data1: { ... },
data2: { ... },
analysis: {
dynamicKey1: <analysisObj>,
dynamicKey...: <analysisObj>,
dynamicKeyN: <analysisObj>
}
}
分析中的键取决于输入的数据类型,并且存在多种可能性。动态键的名称可以在运行之间更改。从测试的角度来看,我对密钥的名称不感兴趣,但是它的analysisObj是一致的。例如,如果我将相同的data1和data2传递给utils.runCommand(),则代表两个对象之间的差额的analysisObj的部分在整体上应该为零。
直到运行脚本后,如果我正在运行100,000个测试,我都没有得到analysisObjs,我不需要不必将所有这些预先运行或预加载到内存或文件系统中。
答案 0 :(得分:1)
我要感谢@JoshLee为我指出一些有用的研究路径。
查看了mocha代码后,主要关注:
我了解到
输出符合预期,结果反映了正确的测试次数。我已经运行了这个自动生成的50,000多个测试,这些测试在1980年的测试套件中使用mochawesome作为报告者而分布不均,并且效果很好。
要实现此目标,需要执行以下5个步骤,这些步骤在下面的更新代码段中进行了说明。
'use strict';
const path = require('path');
const glob = require('glob');
const expect = require('sharedjs/chai-wrapper').expect;
const utils = require('sharedjs/utils');
// Step 1: Pull in Test class directly from mocha
const Test = require('mocha/lib/test');
// Step 2: Simulates it() from mocha/lib/interfaces/bdd.js
// I ignore the isPending() check from bdd.js. I don't know
// if ignoring it is required, but I didn't see a need to add
// it for my case to work
function addTest(suite, title, fn) {
let test = new Test(title, fn);
test.file = __filename;
suite.addTest(test);
return test;
}
let testNum = 0;
let globOpts = { nodir: true }
let type1files = glob.sync(path.join(filetype1_dir, '*'), globOpts);
let type2files = glob.sync(path.join(filetype2_dir, '*'), globOpts);
for (let i = 0; i < type1files.length; i++) {
for (let j = 0; j < type2files.length; j++) {
testNum++;
let testName = utils.mkTestName(testNum, i, j);
// Step 3: Save the suite object so that we can add tests to it.
let suite = describe(testName, function() {
let run;
before(function() {
run = utils.runCommand(type1files[i], type2files[j]);
// run = { status: result.status, command: result.args.join(' '),
// output: fse.readJsonSync(outfile) }
if (run.status !== 0) {
throw new Error(run.status+'='+run.command);
}
for (let key in run.output.analysis) {
// Step 4: Dynamically add tests
// suite is defined at this point since before() is always
// run after describe() returns.
addTest(suite, key+'=0', function() {
expect(run.output.analysis[key].value).to.be.equal('0', key+'=0');
});
}
});
});
// Step 5: Add dummy test in describe() block so that it will be run.
// Can be it() for a pass result or it.skip() for pending.
it('Placeholder for ' + testName, function () {
expect(true).to.be.true;
});
}
}