开玩笑地编写单元测试时会出现特定错误
Posted
技术标签:
【中文标题】开玩笑地编写单元测试时会出现特定错误【英文标题】:Expecting specific error when writing unit tests in jest 【发布时间】:2019-10-05 05:22:31 【问题描述】:我使用nestjs (6.5.0) 和jest (24.8) 并且有一个抛出错误的方法:
public async doSomething(): Promise< data: string, error?: string >
throw new BadRequestException( data: '', error: 'foo' );
如何编写一个单元测试来检查我们是否获得了预期数据的预期异常?显而易见的解决方案是:
it('test', async () =>
expect(await userController.doSomething())
.rejects.toThrowError(new BadRequestException( data: '', error: 'foo');
);
但这不起作用,因为new BadRequestException()
创建了一个具有不同调用堆栈的对象。我该如何测试?
【问题讨论】:
不熟悉 javascript,这可能是一个愚蠢的问题,但是:暂时忽略您正在编写测试 - 在生产代码中,哪里会捕获异常? 生产中的代码异常全部由nestjs处理,最终由浏览器处理。 您找到解决方案了吗? @nilesh-suryavanshi 是的,请参阅下面接受的答案。 【参考方案1】:与jest documentation中的示例相比,您可能会遇到2个问题。
await
应该在 expect
参数之外
rejects
表示抛出了一个错误,所以你测试一下是否相等
类似:
it('test', async () =>
await expect(userController.doSomething())
.rejects.toEqual(new BadRequestException( data: '', error: 'foo');
);
【讨论】:
啊,是的,你说得对,await
应该在外面,我应该测试与rejects
是否相等。但是,这并不能解决主要问题:new BadRequestException
创建了一个新对象,其调用堆栈与doSomething
中的调用堆栈不同。【参考方案2】:
回答我自己的问题:
使用自定义匹配器(见下文),测试可以写成:
it('test', async () =>
await expect(userController.doSomething()).rejects.toContainException(
new BadRequestException( data: '', error: 'foo' ),
);
);
自定义匹配器:
import HttpException from '@nestjs/common';
// ensure this is parsed as a module.
export ;
// https://***.com/questions/43667085/extending-third-party-module-that-is-globally-exposed
declare global
namespace jest
interface Matchers<R>
toContainException: (expected: R | any) => ;
// this will extend the expect with a custom matcher
expect.extend(
toContainException<T extends HttpException>(received: T, expected: T)
const success =
this.equals(received.message, expected.message) &&
this.equals(received.getStatus(), expected.getStatus());
const not = success ? ' not' : '';
return
message: () =>
`expected Exception $received.name$not to be $expected.name` +
'\n\n' +
`Expected: $this.utils.printExpected(expected.message), ` +
`status: $this.utils.printExpected(expected.getStatus()) \n` +
`Received: $this.utils.printReceived(received.message), ` +
`status: $this.utils.printReceived(received.getStatus())`,
pass: success,
;
,
);
【讨论】:
为什么这个答案被否决了?为什么没用?至少它有效。可能有更好的解决方案,但我没有看到任何其他答案或 cmets 可以显示它们。以上是关于开玩笑地编写单元测试时会出现特定错误的主要内容,如果未能解决你的问题,请参考以下文章
如何允许 scss 开玩笑地对 typescript nextjs 进行单元测试?