Sinon单元测试中如何为单个Stub实现动态返回不同测试结果
Sinon实现Stub动态随机返回值的解决方案
问题核心原因
你当前遇到的stub返回值固定问题,本质是JavaScript的参数即时求值逻辑导致的:
- 当你写
sinon.stub(dynamodb, 'get').resolves(stubGet())时,代码执行到打桩这一步,就会立刻运行stubGet()一次,把这次跑出来的结果当成固定参数传给.resolves() - 后面不管业务代码调用多少次打桩的
get方法,拿到的都是这个提前算好的固定值,根本不会再触发stubGet的运行 - 你之前了解的
.onCall()语法也不适用,因为它所有的预设返回值,都是在打桩初始化时就一次性全部生成好的,没法在方法被调用的瞬间动态计算返回结果。
适配需求的实现方式
想要实现每次stub被调用时,实时生成随机返回值、动态覆盖各类分支,不需要用固定值预设的语法,直接通过callsFake给stub绑定自定义的异步实现即可,这种模式下所有逻辑都会在stub被实际调用时才执行。
修改后的打桩代码示例:
sinon.stub(dynamodb, 'get').callsFake(async () => { // 以下逻辑每次stub被调用时才会执行,不会提前运行 const i = Math.round(Math.random() * sampleData.length) const repo = sampleData[i] // 随机命中是否带新推送时间的分支 const isNew = Math.round(Math.random()) === 1 if (isNew) { repo.pushed_at = { S: '1970-01-01T00:00:00Z' } } console.log('repo', repo) const item = { Item: repo } console.log(item) return item })
方案特性
- 完全匹配你的随机测试数据生成需求:每次stub被触发时,才会执行随机数生成、分支判断的逻辑,不会出现初始化阶段固定返回的问题
- 灵活度更高:自定义的fake函数可以直接接收stub方法的调用入参,支持基于入参的动态返回逻辑,比固定索引匹配的
onCall能力更强 - 异步行为兼容:通过async函数实现的fake,会自动将返回值包装为已resolve的Promise,和你之前使用的
.resolves()的异步效果完全一致,不需要改动业务侧的异步调用代码
如果不想把原有
stubGet的逻辑全部挪到fake函数内部,也可以用更简洁的写法:sinon.stub(dynamodb, 'get').callsFake(() => Promise.resolve(stubGet())),运行效果和上面的写法完全一致。
内容的提问来源于stack exchange,提问作者gvasquez
相关产品推荐
相关产品推荐

