如何解读MochaJS单元测试失败时输出的错误信息
Mocha + Chai 单元测试报错排查方法
首先先拆解你贴出的具体报错:这个错误和接口返回状态码没有任何关系,本质是你写断言时调用的response对象本身是undefined,读取should属性时直接触发了类型错误。
先学会读错误栈,不用逐行抠内容
Mocha输出的错误信息优先级从上到下递减,抓核心信息就行:
- 第一行是错误根因:比如你看到的
Uncaught TypeError: Cannot read properties of undefined (reading 'should'),直接说明你在undefined值上访问了should属性,对应到你的代码就是response变量没有被正确赋值。 - 第二行开始找第一个指向你本地测试文件的路径,比如
at C:\...\test.js:53:43,这就是你代码里实际触发错误的位置(第53行43列),直接定位到这行排查即可。 - 后面所有带
node_modules的堆栈行都是依赖包、Node.js内部的调用链路,除非你已经确认自己代码完全没问题,否则不用逐行研究,浪费时间。
先区分三类常见报错,别乱猜问题来源
用Mocha+Chai做接口测试的报错基本可以归为三类,看错误开头就能快速区分:
- 测试代码本身的逻辑/语法错误:就是你遇到的
TypeError、ReferenceError这一类,最常见的原因是异步逻辑没处理对。比如你用chai-http发请求时没加await、没写done回调,请求还没返回、response还没赋值的时候就执行了断言,自然会读到undefined。
给你对比下错误和正确的写法:// 错误写法:没等异步请求返回就执行断言,res是未完成的Promise对象,不是响应结果 it('非法输入返回403', () => { const res = chai.request(app).post('/your-path').send({content: '3rror'}) res.should.have.status(403) }) // 正确写法1:async/await 等请求返回再断言 it('非法输入返回403', async () => { const res = await chai.request(app).post('/your-path').send({content: '3rror'}) res.should.have.status(403) }) // 正确写法2:end回调+done,适合不支持async的旧版本环境 it('非法输入返回403', (done) => { chai.request(app).post('/your-path').send({content: '3rror'}).end((err, res) => { if (err) return done(err) // 先抛出请求本身的网络错误 res.should.have.status(403) done() }) }) - 断言不匹配错误:这才是真正的「接口返回不符合预期」的错误,这类错误以
AssertionError开头,Chai会明确给出期望值和实际值,比如:
看到这类错误才需要排查业务逻辑:如果实际返回200,说明你的输入校验中间件没生效;如果返回500,说明接口内部抛了未捕获的异常;如果返回404,先检查请求路径、请求方法是不是写错了。1) 输入校验 非法输入返回403: AssertionError: expected response to have status code 403 but got 200 + expected - actual -200 +403 - 网络/服务层面错误:比如
ECONNREFUSED就是服务没启动、端口不对连不上;ETIMEDOUT就是接口超时没响应;ENOTFOUND就是请求域名写错了,这类错误和你的断言、业务校验逻辑没关系,先把服务连通性问题解决再跑测试。
固定排查流程,不用瞎试
每次报错按这个顺序走,基本1分钟就能定位问题:
- 看错误第一行,先判断是代码写错了、断言不匹配还是网络问题
- 定位到你自己测试文件里的报错行,先检查这行的变量是不是有值、异步逻辑有没有写对
- 不确定返回值是什么的时候,先加
console.log(err, res)把请求错误、响应内容打出来看,别上来就写断言 - 断言失败时先看实际返回的状态码、响应体内容,再对应去查业务代码的逻辑,不用瞎猜是中间件挂了还是服务没连上
内容的提问来源于stack exchange,提问作者TylerSingleton
相关产品推荐
相关产品推荐

