如何在非并行模式下循环重复运行Mocha测试?
非并行模式下循环运行Mocha测试的问题及解决方法
我想要在非并行模式下循环重复运行Mocha测试,但发现仅第一次迭代会加载测试,后续日志显示0个测试被运行。
主文件代码(需安装Mocha)
const fs = require('fs') const path = require('path'); const Mocha = require('mocha'); getFiles = dir => { // returns tests files as an array const files = [] let resolvedPath = path.resolve(dir); for (const file of fs.readdirSync(dir)) { const fullPath = resolvedPath + '/' + file if (fs.lstatSync(fullPath).isDirectory()) getFiles(fullPath).forEach(x => files.push(file + '/' + x)) else if (file.endsWith('.js')) { files.push(fullPath) } } return files } function delay(time) { // used for sleep within the start function return new Promise(resolve => setTimeout(resolve, time)); } async function start(testsPath) { let testFiles = getFiles(testsPath); let failedTestsCount = -1; while(true) { console.log("starting a new iteration") let mocha = await new Mocha(); for (let i = 0; i < testFiles.length; i++) { mocha.addFile(testFiles[i]); } mocha.parallelMode(false); await mocha.run(failed => { failedTestsCount = failed; }); console.log("Failed tests: " + failedTestsCount) await delay(1000*60) // 1 minute } } start('./tests');
测试文件代码(存储在tests子目录,需安装chai)
let expect = require("chai").expect; describe("Very Simple Tests", async function() { it("passing", async function() { expect(true).to.equal(false); }); it("failing", async function() { expect(true).to.equal(true); }); });
运行输出(仅第一次迭代加载测试)
Very Simple Tests 1) passing ✔ failing 1 passing (3ms) 1 failing 1) Very Simple Tests passing: AssertionError: expected true to equal false + expected - actual -true +false at Context.<anonymous> (tests/tests.js:6:25) at process.processImmediate (node:internal/timers:476:21) starting a new iteration Failed tests: 1 0 passing (0ms)
补充说明:并行模式下运行正常,但某些场景我需要串行模式,尝试过多种配置无效。且无法通过shell脚本和Mocha命令行选项运行,因为需要通过Express端点展示测试结果。
问题原因
Mocha在串行模式下,第一次运行后会将已加载的测试文件标记为已执行,后续重复添加同一文件时会跳过加载;而并行模式下每次都会重新加载文件,因此不存在该问题。
解决方案
要实现非并行模式下的循环运行,需在每次迭代时清除测试文件的模块缓存,并正确封装Mocha的运行逻辑为Promise。修改后的主文件代码如下:
const fs = require('fs') const path = require('path'); const Mocha = require('mocha'); function getFiles(dir) { // 返回测试文件数组 const files = [] const resolvedPath = path.resolve(dir); for (const file of fs.readdirSync(dir)) { const fullPath = path.join(resolvedPath, file); // 用path.join避免路径拼接问题 if (fs.lstatSync(fullPath).isDirectory()) { getFiles(fullPath).forEach(subFile => files.push(subFile)); } else if (file.endsWith('.js')) { files.push(fullPath); } } return files } function delay(time) { // 用于循环中的延迟 return new Promise(resolve => setTimeout(resolve, time)); } async function start(testsPath) { const testFiles = getFiles(testsPath); while(true) { console.log("starting a new iteration"); // 清除测试文件的模块缓存,确保每次重新加载 testFiles.forEach(file => { delete require.cache[require.resolve(file)]; }); const mocha = new Mocha(); mocha.parallelMode(false); // 重新添加测试文件 testFiles.forEach(file => mocha.addFile(file)); // 正确封装mocha.run为Promise,等待测试完成 const failedTestsCount = await new Promise(resolve => { mocha.run(failed => resolve(failed)); }); console.log("Failed tests: " + failedTestsCount); await delay(1000*60); // 1分钟延迟 } } start('./tests');
关键修改点
- 清除模块缓存:通过
delete require.cache[require.resolve(file)]删除已加载的测试文件缓存,确保Node.js每次都重新读取并执行测试代码 - 修正Promise封装:原代码直接
await mocha.run()无效,因为mocha.run()不返回Promise,需手动封装以正确等待测试结束 - 路径优化:用
path.join替代字符串拼接,避免跨平台路径兼容性问题
修改后,串行模式下每次循环都会重新加载并执行所有测试用例,与第一次运行结果一致。
内容的提问来源于stack exchange,提问作者npocmaka
相关产品推荐
相关产品推荐

