在使用 Chai 断言库进行测试时,expect(...).to.throw()
和 expect(...).to.be.rejectedWith()
是两种不同的断言方式,主要用于验证不同类型的错误抛出:
1. expect(...).to.throw()
- 用途:验证同步函数调用是否抛出错误。
- 适用场景:普通函数、构造函数、同步方法等。
- 示例:
1
2
3
4
5
6
7
8
9
10// 同步函数抛出错误
function throwError() {
throw new Error('Something went wrong');
}
// 断言同步函数调用会抛出错误
expect(throwError).to.throw('Something went wrong');
// 也可以用于方法调用(用箭头函数包裹)
expect(() => game.addPlayer(player)).to.throw('玩家已存在');
2. expect(...).to.be.rejectedWith()
- 用途:验证异步操作(Promise)是否被拒绝(rejected)并携带特定错误信息。
- 适用场景:异步函数、返回 Promise 的方法等。
- 示例:
1
2
3
4
5
6
7
8
9
10// 异步函数返回 rejected Promise
async function asyncThrowError() {
throw new Error('Async error');
}
// 断言异步操作会被拒绝并携带特定错误
await expect(asyncThrowError()).to.be.rejectedWith('Async error');
// 或对返回 Promise 的方法进行断言
await expect(game.joinAsync(player)).to.be.rejectedWith('游戏已满');
关键区别总结
特性 | expect(...).to.throw() |
expect(...).to.be.rejectedWith() |
---|---|---|
验证对象 | 同步函数调用 | 异步操作(Promise) |
语法要求 | 需要传入函数引用(或用箭头函数包裹) | 直接传入 Promise 或使用 await |
错误类型 | 捕获同步抛出的错误(throw) | 捕获 Promise 被拒绝(reject)的情况 |
异步测试支持 | 不支持(无法直接验证 Promise) | 必须使用(支持 async/await ) |
示例 | expect(() => fn()).to.throw() |
await expect(promise).to.be.rejected() |
常见误区
误用
to.throw()
测试异步代码:1
2
3
4
5// 错误:无法捕获 Promise 的拒绝
expect(game.joinAsync(player)).to.throw();
// 正确:使用 rejectedWith
await expect(game.joinAsync(player)).to.be.rejectedWith('错误信息');忘记
await
关键字:1
2
3
4
5// 错误:断言会立即执行,不会等待 Promise 完成
expect(game.joinAsync(player)).to.be.rejectedWith('错误信息');
// 正确:等待 Promise 完成
await expect(game.joinAsync(player)).to.be.rejectedWith('错误信息');
何时使用哪个?
- 同步代码(普通函数、方法):使用
to.throw()
。 - 异步代码(返回 Promise 的函数/方法):使用
to.be.rejectedWith()
,并确保测试函数为async
且使用await
。
如果你的 addPlayer
方法是同步的(如最初代码所示),则应使用 to.throw()
;如果该方法改为异步(返回 Promise),则需使用 to.be.rejectedWith()
。