如何在测试递归函数时让Jasmine测试在X秒后终止
测试递归函数超时的解决方案
同步递归会阻塞JavaScript事件循环,你之前用setTimeout结合fail()或抛错误的方式无效,核心原因是递归函数一直占用主线程,setTimeout的回调根本没机会执行。以下是可行的解决办法:
1. 利用测试框架内置超时(以Jest为例)
Jest支持给单条测试用例设置超时阈值,直接在it方法末尾添加超时毫秒数即可:
describe("if provided with an invalid sudoku grid", () => { it("should timeout", () => { const result = solve(unSolveAble); }, 5000); // 5秒后测试自动超时失败 });
注意:如果递归是完全同步阻塞的,Jest的内置超时可能无法立即终止它——因为主线程被递归占满,Jest的超时检测逻辑也无法执行。这种情况需要配合异步改造或线程隔离方案。
2. 将递归函数改造为异步可中断版本
在递归步骤中加入await Promise.resolve(),主动让出主线程,让超时逻辑有机会执行:
// 改造solve为异步版本 async function solveAsync(grid) { // 每次递归前让出主线程 await Promise.resolve(); // ... 原递归逻辑代码 } // 测试用例 describe("if provided with an invalid sudoku grid", () => { it("should timeout", async () => { // 用Promise.race让执行逻辑和超时逻辑赛跑 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error("Test timed out")), 5000); }); await Promise.race([solveAsync(unSolveAble), timeoutPromise]); }); });
3. Node.js环境下用worker_threads隔离同步递归
如果不想修改原递归函数,可将递归逻辑放到子线程中,主线程独立监听超时:
const { Worker } = require('worker_threads'); describe("if provided with an invalid sudoku grid", () => { it("should timeout", (done) => { const worker = new Worker('./solve-worker.js', { workerData: unSolveAble }); const timeoutId = setTimeout(() => { worker.terminate(); // 强制终止子线程 done(new Error("Test timed out")); }, 5000); worker.on('message', () => { clearTimeout(timeoutId); done(new Error("Function completed unexpectedly")); }); worker.on('error', (err) => { clearTimeout(timeoutId); done(err); }); }); });
对应的solve-worker.js文件:
const { parentPort, workerData } = require('worker_threads'); const solve = require('./your-solve-function-path'); const result = solve(workerData); parentPort.postMessage(result);
内容的提问来源于stack exchange,提问作者RubenSmn
相关产品推荐
相关产品推荐

