AVA.js并行测试场景下如何对Date、Math等全局对象进行mock
AVA.js 并行测试下全局对象Mock的正确方案
AVA默认会并行运行同一文件内的测试用例,直接修改全局对象会导致多用例的mock互相干扰,可根据场景选择以下三种无冲突的处理方案:
方案1:使用AVA内置t.mock能力(4.0+版本推荐)
AVA自带的mock方法默认绑定到单个测试的上下文,测试运行结束后会自动恢复原方法,不会影响其他并行执行的用例
- 单测试用例mock示例:
import test from 'ava'; test('mock Date.now返回固定时间', t => { const fixedTime = 1690000000000; t.mock.replace(Date, 'now', () => fixedTime); t.is(Date.now(), fixedTime); // 该mock仅在当前用例生效 });
- 全文件通用mock可通过
beforeEach为每个用例生成独立实例:
import test from 'ava'; test.beforeEach(t => { t.context.mockDate = t.mock.replace(Date, 'now', () => 1690000000000); }); test('测试用例1', t => { // 单独修改当前用例的mock返回值,不影响其他用例 t.context.mockDate.returns(1700000000000); t.is(Date.now(), 1700000000000); }); test('测试用例2', t => { t.is(Date.now(), 1690000000000); });
方案2:依赖注入彻底规避全局依赖
改写业务代码,把需要用到的全局对象作为可选参数注入,测试时直接传入mock实例,完全不需要修改全局对象
- 业务代码改写示例:
// 原写法:直接依赖全局Date export const getTime = () => Date.now(); // 改写后:支持注入自定义时间工具 export const getTime = (dateUtil = Date) => dateUtil.now();
- 测试代码示例:
import test from 'ava'; import { getTime } from './util.js'; test('返回固定时间', t => { const mockDate = { now: () => 1690000000000 }; t.is(getTime(mockDate), 1690000000000); });
方案3:用sinon沙箱实现多对象批量隔离
如果需要同时mock多个全局对象,可使用sinon的沙箱能力,每个用例生成独立沙箱,结束后批量恢复所有修改
import test from 'ava'; import sinon from 'sinon'; test.beforeEach(t => { // 每个用例创建独立沙箱 t.context.sandbox = sinon.createSandbox(); }); test.afterEach(t => { // 自动恢复该用例所有mock修改 t.context.sandbox.restore(); }); test('同时mock Date和Math.random', t => { const { sandbox } = t.context; sandbox.stub(Date, 'now').returns(1690000000000); sandbox.stub(Math, 'random').returns(0.6); t.is(Date.now(), 1690000000000); t.is(Math.random(), 0.6); });
注意:禁止直接在测试文件顶层、全局before钩子中修改全局对象,这类修改会被所有并行用例共享,必然出现冲突。
内容的提问来源于stack exchange,提问作者BuffUp
相关产品推荐
相关产品推荐

