You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mocha+Chai+Sinon测试异常:Promise中called属性始终为true的原因及解决

为什么Sinon中即使函数未定义,called属性也总是返回true?

我来帮你拆解这个问题——你遇到的这个“无论什么函数,called都返回true”的假象,其实大概率是Promise错误处理不当导致的,再加上可能的Spy引用问题,咱们一步步说:

核心原因:Promise的catch块没有传递错误给Mocha

看你的测试代码里的catch部分:

.catch(err => {
  done();
});

如果你的断言(比如expect(instance.view.startCountDown.called).to.be.ok)失败,会抛出一个错误,这个错误会被Promise的catch捕获。但你在这里直接调用done(),没有把错误传递给它,Mocha就会认为测试“成功完成”,而不会知道断言已经失败了!

换句话说,不是called属性真的返回true,而是断言失败的错误被你吞掉了,导致你误以为测试通过了。

另外还有一个可能的小坑:如果你断言的不是Sinon Spy对象的called属性,而是普通函数甚至未定义的属性,JavaScript的特性会让结果超出预期:

  • 如果你访问一个普通函数的called属性(不是Sinon Spy),这个属性不存在,会返回undefined,而Chai的to.be.ok会把undefined判定为falsy,断言应该失败——但因为你吞掉了错误,所以看起来像是通过了。
  • 如果不小心创建了全局的called变量(比如漏写了let/const),那访问任何对象的called属性都可能拿到这个全局值,导致误判。

解决方案

1. 修复Promise的错误处理

在catch块里把错误传递给done(),让Mocha捕获到断言失败:

result.then(res => {
  expect(instance.view.startCountDown.called).to.be.ok;
  done();
}).catch(err => {
  done(err); // 关键:把错误传给done,Mocha才会标记测试失败
});

或者更推荐用async/await简化代码,避免手动处理done,错误会自动被Mocha捕获:

it('if get server response success, should start countdown', async function () {
  // given
  sandbox.stub(model, 'getVerifyCode').resolves({});
  sandbox.spy(view, 'startCountDown');
  // when
  await instance.onClickVerify('123456');
  // then
  expect(instance.view.startCountDown.called).to.be.ok;
});

2. 确保Spy的引用正确

确认你Spy的view和instance.view是同一个对象引用。如果instance.view是测试前就创建的实例,而你Spy的是另一个view对象,那你的Spy根本不会生效。可以在测试里加一行验证:

console.log(instance.view === view); // 应该输出true

3. 排查全局变量污染

检查你的代码里有没有不小心写了called = true这种没有声明的变量,这会创建全局的called变量,导致意外的truthy值。

验证方法

先把catch块改成传递错误给done(),再运行测试——这时候如果startCountDown没被调用,或者你断言未定义的函数,测试会正确失败,而不是之前的“假通过”。

内容的提问来源于stack exchange,提问作者kHRYSTAL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:49:20