应先验证错误类型再校验message内容:同步函数用toThrow或toThrowError配合message断言,异步函数须用rejects.toThrow;推荐组合类型与message双重校验,避免仅依赖易变的错误文本。

要测试函数是否抛出包含特定文字的错误消息,关键不是只检查“有没有报错”,而是验证错误对象的 message 属性是否精确匹配预期内容。直接用字符串断言最直观,但要注意匹配方式和框架差异。
用 toThrow 匹配错误消息(推荐初阶用法)
Jest 和 Vitest 都支持 toThrow() 接收字符串或正则,适合快速验证提示是否对用户友好:
-
expect(() => parseEmail('abc')).toThrow('Invalid email format')—— 精确匹配整个 message 字符串 -
expect(() => parseEmail('abc')).toThrow(/email/i)—— 不区分大小写、匹配子串,更宽松也更健壮 - 避免写成
.toThrow('email')这类过于宽泛的匹配,容易误判
先捕获再断言 message(适合需要多属性校验)
当还需同时检查错误类型、code 或堆栈等字段时,应先获取错误实例,再分项断言:
- Vitest 示例:
const err = expect(() => validateUser({})).toThrowError();<br>expect(err.message).toBe('Name is required');<br>expect(err.code).toBe('MISSING_FIELD'); - Jest 支持链式:
expect(() => validateUser({}))<br> .toThrowError()<br> .toHaveProperty('message', 'Name is required');
注意异步函数不能直接用 toThrow
async 函数返回 Promise,必须用 rejects 配合 await:
await expect(fetchUser('invalid-id')).rejects.toThrow('User not found');- 若需校验 message 子串:
await expect(apiCall()).rejects.toThrow(/timeout/); - 错误写法:
expect(() => fetchUser('id')).toThrow(...)—— 这会立即失败,因返回的是 Promise 而非同步错误
避免只靠 message 判断,补充类型校验更可靠
仅靠 message 容易因拼写调整或翻译变动导致测试失败。建议组合使用:
- 优先用
toThrowError(TypeError)或toThrowError(ValidationError)锁定错误类 - 再加
.toHaveProperty('message', ...)确保提示一致 - 自定义错误类中 message 应为只读且不可变,避免运行时动态拼接











