Node.js下Mocha与Chai如何正确搭配should断言与done回调
疑问根因解析
为什么修改断言属性名后测试依然通过
这种情况属于典型的测试流程和异步逻辑脱钩的假象,并不是断言校验真的通过:
- 当前的
it用例回调是同步执行的,既没有返回Promise,也没有声明done形参供Mocha追踪测试状态 - Mocha在同步执行完
it回调的代码(也就是刚触发那个自执行async函数的执行)之后,就会立刻判定当前用例执行完成,默认标记为通过 - 后续async函数里的
await逻辑、控制台输出、Chai断言,都是在Mocha已经走完测试流程之后才异步执行的。哪怕断言抛出“目标对象不存在对应属性”的错误,这个错误也和Mocha的测试判断完全隔离,根本不会被Mocha捕获,所以不管你把断言的属性名改成什么,用例都会显示通过。
为什么取消done注释后会报超时错误
报错的核心是没有按照Mocha的规则传递done回调:
- Mocha只有在检测到
it的回调接收了done形参时,才会进入“等待手动标记完成”的模式 - 你当前的
it回调没有声明done形参,代码执行到内部的done()时,既拿不到Mocha注入的done方法,也没法正确触发完成信号 - 这种情况下Mocha一直处于等待状态,等默认的2秒超时时间到了,就会抛出对应的超时错误。
正确的异步测试编写方式
Mocha对异步测试的支持有两种合规写法,二选一即可,不要混用:
写法1:Promise返回模式(更推荐,配合async/await更简洁)
不需要手动写自执行函数,也不需要调用done,直接把async作为it的回调即可,Mocha会自动追踪Promise的状态:
it("should add user to db", async () => { let id = 4; let name = "Alen"; let result = await UserService.addUser(id, name); console.log("result", result); // 断言抛出的错误会被Mocha自动捕获,直接标记用例失败 result.should.have.property("_id"); })
这种写法下如果把断言的属性名改成不存在的_i,Mocha会直接捕获断言抛出的错误,判定用例不通过,不会再出现之前“测试通过但断言没生效”的假象。
写法2:手动结合done回调的写法
如果需要用done回调,必须严格按照规则处理:
- 把
done作为it回调的第一个形参,让Mocha识别到你需要手动标记测试完成 - 必须覆盖成功、失败两种分支的done调用,不能只在成功逻辑里写done,避免出现断言抛错后done永远不被调用的超时问题
it("should add user to db", (done) => { let id = 4; let name = "Alen"; UserService.addUser(id, name) .then((result) => { console.log("result", result); result.should.have.property("_id"); // 断言通过后再调用done标记测试完成 done(); }) .catch((err) => { // 不管是服务调用失败,还是断言抛出错误,都把错误传给done,让Mocha直接标记用例失败 done(err); }); })
注意:不要同时给
it回调声明done形参又返回Promise,这种双重标记测试完成的写法会触发Mocha的冲突报错。
内容的提问来源于stack exchange,提问作者Rajat kashyap
相关产品推荐
相关产品推荐

