为什么简单布尔校验的Jest测试比控制台测试慢很多还超时崩溃
问题原因及解决方案
Jest 完全支持 for 循环语法,测试超时和循环本身无关,根本原因是 generateMove 函数内部出现死循环,超出了 Jest 默认的测试超时时间(通常为 5 秒)。
常见触发原因
已占用列表不同步
你的generateMove函数的防重复校验逻辑,依赖的已占用位置列表和测试代码中手动维护的alreadyPlayed不是同一份:- 如果
generateMove设计为需要接收外部已占用列表作为入参,你在测试调用时没有传入该参数,函数内部会基于空列表做校验,返回的位置可能和之前返回的重复,当你调用到第 N 次时,棋盘实际已被占满,但函数内部认为还有空位,就会一直循环随机查找可用位置,触发死循环。 - 如果
generateMove内部通过闭包、模块顶层变量等方式自行维护已占用列表,Jest 运行测试时默认会共享模块状态,前一次测试跑完后内部已占用列表已经存满 100 个位置,后续测试再调用该函数时,永远找不到可用位置,直接进入死循环。
- 如果
函数内部容错缺失
generateMove没有做边界校验:当棋盘所有位置都被占用时,没有抛出明确错误,而是直接进入无限重试的逻辑,问题无法被直接感知,只会表现为超时。
修复方案
- 如果
generateMove需要外部传入已占用列表,修改测试代码,每次调用都传入当前维护的已占用数组:test('ai does not hit places that were already hit', () => { const alreadyPlayed = []; for (let i=0;i<99;i++) { const move = generateMove(alreadyPlayed); alreadyPlayed.push(move); } const last = generateMove(alreadyPlayed); expect(alreadyPlayed.includes(last)).toBe(false); }) - 如果
generateMove内部自行维护状态,新增状态重置方法,每次测试执行前清空内部已占用列表:// 每次测试运行前重置 generateMove 内部状态 beforeEach(() => { generateMove.reset(); }) test('ai does not hit places that were already hit', () => { const alreadyPlayed = []; for (let i=0;i<99;i++) { alreadyPlayed.push(generateMove()); } const last = generateMove(); expect(alreadyPlayed.includes(last)).toBe(false); }) - 给
generateMove增加边界校验,当检测到所有位置都被占满时直接抛出错误,避免无意义的死循环:// generateMove 内部新增逻辑示例 if (takenList.length >= 100) { throw new Error('棋盘所有位置已被占用'); }
内容的提问来源于stack exchange,提问作者homeworkmon
相关产品推荐
相关产品推荐

