使用Chai测试TypeScript错误抛出时遭遇测试失败问题
解决Chai测试无法捕获Express中间件抛出错误的问题
我之前也碰到过一模一样的情况——明明代码里已经抛出了指定错误,但Chai测试就是检测不到。大概率是Express的错误处理逻辑和测试里的异步代码处理没配合好,咱们一步步捋清楚问题:
先理清楚你的核心代码问题
先把你截断的users.ts补全并标注关键细节:
// users.ts const database = require('../databases/postgres'); module.exports = { create: async (req, res, next) => { try { if (!req.body.email) { throw new Error('email needed'); } // 注意:这里的user变量未定义,应该是req.body? const userCreated = await database.createUser(req.body); userCreated ? res.status(200).send('success') : res.status(400).send('failed'); } catch (err) { // 重点!必须调用next(err)把错误传给Express的错误处理链 next(err); } } };
问题根源分析
- Express异步中间件的错误传递:如果在
catch块里不调用next(err),Express会悄悄吞掉这个错误,测试根本拿不到错误信息。 - Chai异步测试的处理方式:测试异步代码时,要么用
done()回调,要么用async/await,否则测试会提前结束,误以为没有错误抛出。 - 缺少自定义错误处理中间件:Express默认的错误处理不会把错误信息返回给客户端,测试自然捕获不到指定的错误文本。
正确的Chai测试写法(以chai-http为例)
假设你的测试文件是users.test.js,按照下面的方式编写测试:
const chai = require('chai'); const chaiHttp = require('chai-http'); const app = require('../app'); // 你的Express实例 const expect = chai.expect; chai.use(chaiHttp); describe('User Creation API', () => { // 用done()回调的写法 it('should return "email needed" error when email is missing', (done) => { chai.request(app) .post('/users') // 对应你的create路由 .send({}) // 不传email参数 .end((err, res) => { expect(res).to.have.status(400); // 匹配你自定义的错误状态码 expect(res.text).to.equal('email needed'); // 匹配抛出的错误信息 done(); // 必须调用done结束异步测试 }); }); // 更简洁的async/await写法 it('should throw "email needed" error when email is missing (async/await)', async () => { try { const res = await chai.request(app).post('/users').send({}); // 如果走到这一步,说明没抛出预期错误,直接断言失败 expect.fail('Expected an error but none was thrown'); } catch (err) { expect(err.response).to.have.status(400); expect(err.response.text).to.equal('email needed'); } }); });
别忘了加Express错误处理中间件
在你的app.js里必须添加自定义错误处理中间件,把错误信息返回给客户端:
// app.js // ...其他路由配置... // 错误处理中间件(必须放在所有路由之后) app.use((err, req, res, next) => { console.error(err.stack); // 这里返回你需要的状态码和错误信息 res.status(400).send(err.message); });
最后再检查两个细节
- 确认你的
create中间件里的catch块确实调用了next(err),否则错误无法传递到处理链。 - 检查代码里的变量是否正确:比如你原来的
database.createUser(user)里的user是否是req.body,未定义的变量会抛出其他错误,干扰测试结果。
内容的提问来源于stack exchange,提问作者Langlois.dev
相关产品推荐
相关产品推荐

