【问题标题】:Test async function to throw with mocha测试异步函数以使用 mocha 抛出
【发布时间】:2018-10-02 21:03:38
【问题描述】:

我有一个运行 2000 毫秒的异步函数,然后它会抛出异常。我正在尝试用 Mocha / chai 准确地测试这种行为,但显然我做错了。

这就是我尝试过的:

第一:

expect(publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000)).to.eventually.throw();

这将测试标记为通过(52 毫秒运行时间),但 2 秒后抛出异常。所以显然它根本没有等待该功能的承诺。

第二:

expect(async () => {
      await publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000);
    }).to.throw();

测试失败: 应该在预定义的超时后拒绝预定的消息: AssertionError:预期 [Function] 会抛出错误 在 Context.mocha_1.it (test\integration\rpc-communication.spec.ts:75:16) 在

预期的行为是测试通过,因为 2000 毫秒后抛出异常,这是在给定的测试用例超时 4000 毫秒内。

其他信息:

这会奏效。承诺因错误而被拒绝(我也可以将其更改为使用字符串拒绝)。这应该证明 dispatchMessage() 正在按预期工作。测试用例耗时 2002ms,然后通过。

    try {
      await publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000);
    } catch (err) {
      expect(err).to.be.an('Error');
    }

问题:

如何正确测试异步函数是否引发异常?

【问题讨论】:

    标签: typescript mocha.js chai chai-as-promised


    【解决方案1】:

    .to.throw() 不应该在 async 函数上工作,因为它不会抛出错误,而是返回被拒绝的承诺。

    这个问题是 chai-as-promised 特有的。如this issue 中所述,.to.eventually.throw() 将无法按预期工作。它断言一个promise resolves 带有一个在调用时会同步throw 错误的函数。 dispatchMessage 中可能不会发生这种情况。

    这取决于dispatchMessage,但可能应该是:

    expect(publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000))
    .to.be.rejected;
    

    【讨论】:

    • 显然这种方法也不起作用。所有测试在 48 毫秒内通过。返回的 Promise dispatchMessage 将在被调用 2s 后被拒绝。Tslint 也突出显示了这一行,因为 [tslint] unused expression, expected an assignment or function call (no-unused-expression)
    • 这是 Chai 的常见问题。禁用此规则或使用 npmjs.com/package/tslint-no-unused-expression-chai 。这就是应该如何测试异步(如'async..await')函数的方式。从您发布的代码中看不到 dispatchMessage 返回一个被拒绝的承诺。考虑为 dispatchMessage 提供源代码。
    • 感谢您提供的信息。我在原始线程中添加了另一个 sn-p,这应该证明 dispatchMessage 可以按预期工作。不过,我不想每次想测试异步函数时都使用 try / catch。 dispatchMessage 的代码有点复杂,因为它使用延迟承诺(它实际上将网络事件转换为承诺,但它使用超时)。在这种情况下,我想测试延迟的承诺超时。
    • 你能提供你的规范的源代码而不是截断只是 sn-ps 吗?如果规范函数是 asyncawait expect... 或返回一个承诺 return expect...,您应该链接一个 expect 返回的承诺。我想这就是您遇到 TSLint 错误的原因。该错误将出现在其他 Chai 断言中,因为 Chai 就是这样工作的,但对于这个,应该使用表达式。
    • 需要等待期望,我不知道。您的方法现在确实有效,非常感谢!
    【解决方案2】:

    Chai 支持 async/await 测试功能。要断言 Promise 被拒绝,您可以使用 chai-as-promise 插件中的 rejectedrejectedWith

    因为rejected 返回一个promise,你需要一个await 否则测试用例在promise 被拒绝之前完成。

    it('should be rejected', async () => {
      await expect(
        publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000)
      ).to.be.rejected;
    }
    

    【讨论】:

      【解决方案3】:

      其他答案对我不起作用(也许我没有正确的 Chai 版本?),所以这就是我的解决方法。

      首先,定义这个util函数:

      const shouldReject = async (promise:Promise<any>, errorClass?:Function|Error, message?:string):Promise<void> => {
        let error = null;
        try {
          await promise;
        }
        catch (e) {
          error = e;
        }
        expect(error).to.not.be.null;
        if(errorClass !== undefined)
          error.should.be.an.instanceOf(errorClass);
        if(message !== undefined)
          error.message.should.equal(message);
      };
      

      在您的示例中,您可以像这样使用它:

      it('should be rejected', async () => {
        await shouldReject(
          publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000)
        );
      }
      

      【讨论】:

        猜你喜欢
        • 2015-04-04
        • 2012-09-29
        • 1970-01-01
        • 2012-08-22
        • 2014-02-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多