【问题标题】:How to test if a void async function was successful with jest?如何测试一个 void async 函数是否成功与 jest?
【发布时间】:2019-08-09 11:57:36
【问题描述】:

你如何简明地测试一个 void 异步函数是否成功地用 jest 执行?我正在使用 TypeScript。

// foo.ts
export class Foo {
  public async bar(): Promise<void> {
    await someAsync();
  }
}

如何测试new Foo().bar() 不会抛出错误?

【问题讨论】:

    标签: typescript promise jestjs void


    【解决方案1】:

    这是我发现的最符合语义的方式。 它甚至只是测试名称的翻译。

    describe("Foo.bar()", () => {
          test("Should not throw", async () => {
            await expect(new Foo().bar()).resolves.not.toThrow();
          });
        });
    

    【讨论】:

    • 迄今为止的最佳答案
    • 对于像我一样错过它的人来说,await 非常重要。如果您省略它,那么测试将始终通过。虽然我手头没有其他选择,但我更喜欢在语法上不可能出现这种错误的选择。
    • @TobySmith 我发现的最佳解决方案是标记未处理的承诺(即缺少等待/无效)的 linter,例如 eslint。
    【解决方案2】:

    Promise 的优点是它根本不应该抛出,而是被解决或拒绝。另一方面,toBe() 断言需要一个参数,即使 TypeScript 中有一个 Promise&lt;void&gt;

    那么如果没有传递参数(或者参数是无效的)但它仍然被评估怎么办。参数是undefined

      test("Should resolve", async () => {
          await expect(new Foo().bar()).resolves.toBe(undefined);
      });
    

    测试not.toThrow() 对我来说碰巧是个假朋友,因为我的Foo.bar() 没有抛出,也没有解决。

    【讨论】:

    • 你可以使用 .toBeUndefined() 匹配器来测试未定义
    • 这似乎是最新的答案。我的用法:expect(fs.access(path, mode.R_OK)).resolves.toBeUndefined()
    【解决方案3】:

    这是我找到的最好方法。希望有更优雅的东西。

    describe("Foo.bar()", () => {
      it("should not throw", async () => {
        expect.assertions(1);
    
        try {
          await new Foo().bar();
          expect(true).toBeTruthy();
        } catch {
          // should not come here
        }
      });
    });
    

    【讨论】:

    • 也不需要 try catch(await 就足够了),因为如果 promise 不成功,测试无论如何都会失败。
    【解决方案4】:

    ...替代方案是resolves 断言。

    describe("Foo.bar()", () => {
      it("should not throw", () => {
          return expect(new Foo().bar()).resolves.toEqual();
      });
    });
    

    在这里你必须返回结果,因为它是一个 Promise(并让你开玩笑等到它完成)。如果您只需要验证已解决(或被拒绝 - 有类似的道具 rejects 用于检查拒绝值),它会稍微简洁一些。

    但是如果你需要在基于 promise 的函数运行后运行几次检查

    describe("Foo.bar()", () => {
      it("should not throw", () => {
          const promise = new Foo().bar()
          expect(promise).resolves.toEqual();
          expect(someMock).toHaveBeenCalled();
          return promise;
      });
    });
    

    您可能会发现async/await 的选项更...令人满意?

    PS 至于你的变种

    describe("Foo.bar()", () => {
      it("should not throw", async () => {
        expect.assertions(1);
    
        try {
          await new Foo().bar();
          expect(true).toBeTruthy();
        } catch {
          // should not come here
        }
      });
    });
    

    我相信不需要捕获错误 - 所以expect.assertions 也变得多余。为什么?未捕获的异常将使您的测试失败,并且预计不会出现异常,因此失败也没关系。如果您期望异常并想要检查其属性,则需要这样的结构。

    如果测试失败选项expect.assertions 将通知您它失败了,而未捕获的异常将突出显示特定语句(如果测试有多个可能出现异常的语句,则很有用)

    [UPD] 我也错过了您需要检查承诺是否通过 any 结果解决的初始点(我的版本检查它是否通过 undefined 解决,这不是一个很好的举动(它没有如果函数开始返回 something (如果它之前返回 nothing)会毁掉任何东西)。同时我们应该至少有一个 check in test...

    所以也许你使用存根expect(true) 的方法在这里是一样合法的。

    但如果您不想在同一个测试用例中生成更多 expect,我会验证两次。被测试的陈述真的如此孤立吗?或者您只是将相关检查分解为单独的it()

    【讨论】:

      猜你喜欢
      • 2020-06-22
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      • 2020-12-25
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多