开玩笑地编写单元测试时会出现特定错误

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 进行单元测试?

开玩笑单元测试检查唯一值

createWriteStream 的 ('error') 上的开玩笑单元测试

如果调用 super() 则开玩笑的单元测试

调度程序没有在开玩笑的单元测试中注册回调

ReferenceError:未定义窗口。当我通过 jest 运行 npm test 进行单元测试时出现此错误