测试含随机数或时间副作用的函数,关键在于将不确定性外置:1. 用参数注入替代全局调用(如传入random/now函数);2. 用Jest等工具mock全局方法;3. 将副作用封装为独立可测函数;4. 避免模糊断言,坚持确定性验证。

测试带有随机数或当前时间副作用的函数,关键在于控制不确定性——把随机性或时间依赖从函数内部“抽出来”,换成可预测、可模拟的输入,让函数变成纯函数或行为可控的函数。
用参数替代全局副作用
把 Math.random() 或 Date.now() 这类调用,改为由外部传入。这样测试时就能传固定值,结果完全可预期。
- 改写前(难测):
return `id-${Math.random().toString(36).substr(2, 9)}-${Date.now()}`;
}
- 改写后(易测):
return `id-${random().toString(36).substr(2, 9)}-${now()}`;
}
测试时传入模拟函数:
test('generateId', () => {const mockRandom = () => 0.12345;
const mockNow = () => 1717000000000;
expect(generateId(mockRandom, mockNow)).toBe('id-12345-1717000000000');
});
用测试替身(Spy / Mock)拦截全局方法
如果无法修改源码(如第三方库封装),可用 Jest 等测试框架临时替换全局方法。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- Jest 中 mock
Math.random:
jest.spyOn(Math, 'random').mockReturnValue(0.42);
expect(myRandomFunction()).toBe('result-for-0.42');
Math.random.mockRestore(); // 恢复原行为
});
- Mock
Date构造函数(影响new Date()和Date.now()):
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01T12:00:00Z'));
expect(new Date().toISOString()).toBe('2024-01-01T12:00:00.000Z');
jest.useRealTimers();
});
封装副作用为独立函数并单独测试
把随机/时间逻辑抽成小函数,单独验证其行为,主逻辑只负责组合。
- 例如:
Math.random().toString(36).substr(2, len);
const getTimestamp = () => Date.now();
function createEvent() {
return { id: `${getRandomString()}-${getTimestamp()}` };
}
这样你可以分别测试 getRandomString 是否输出合法字符,getTimestamp 是否返回数字,而 createEvent 的测试只需 mock 这两个依赖(或用上文参数注入方式)。
避免在测试中依赖真实随机或时间
不要写类似 expect(result).toMatch(/id-[a-z0-9]+-\d+/) 这种模糊断言——它绕过了正确性验证,只是检查格式,漏掉逻辑错误。
- 真正要测的是:给定某随机值和某时间点,输出是否严格符合预期
- 哪怕函数本身“应该”随机,单元测试也必须确定性地覆盖边界情况(如最小/最大随机值、闰秒、时区切换等)

















