typescript 测试异步函数以抛出mocha

bqujaahr  于 2022-12-01  发布在  TypeScript
关注(0)|答案(4)|浏览(135)

我有一个运行2000 ms的异步函数,然后它会抛出一个异常。我试图用Mocha / chai测试这个行为,但显然我做错了。
"我也试过“

名字:

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

这会将测试标记为通过(52 ms运行时间),但在2s后抛出一个异常,因此很明显它根本没有等待该函数的承诺。

第二位:

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

测试失败:应在预定义超时后拒绝预设消息:Assert错误:预期[函数]会在上下文中抛出错误。mocha_1.it(test\integration\rpc-communication.spec.ts:75:16),位置为
预期行为是测试通过,因为在2000 ms后抛出异常,这在给定的测试用例超时4000 ms内。

其他信息:

这是可行的。promise被拒绝,并显示一个错误(我也可以将其更改为reject,并显示一个字符串)。这应该证明dispatchMessage()按预期工作。测试用例花费了2002 ms,然后通过。

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

问题:

如何正确测试异步函数是否抛出异常?

j2qf4p5b

j2qf4p5b1#

.to.throw()不应该在async函数上工作,因为它不会抛出错误,而是返回被拒绝的承诺。
这个问题是chai-as-promise特有的。正如this issue中所解释的,.to.eventually.throw()不会像预期的那样工作。它Assert一个promise * 解析 * 了一个函数,该函数在被调用时会同步 * 抛出 * 错误。这可能不是dispatchMessage中所发生的情况。
这取决于dispatchMessage,但可能应为:

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

mzillmmw2#

Chai支持async/await测试函数。要Assertpromise拒绝,您可以使用 chai-as-promise 插件中的rejectedrejectedWith
因为rejected返回一个承诺,所以你需要一个await,否则测试用例在承诺被拒绝之前完成。

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

yyyllmsg3#

要使其他答案起作用,必须使用chai-as-promised(它们不适用于现成的chai)。
例如:

const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');

chai.use(chaiAsPromised);

较早的答案(用于历史记录)
其他的答案对我不起作用(也许我没有正确的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)
  );
}
yshpjwxd

yshpjwxd4#

我发现在chaimocha中预期被拒绝的承诺的最简洁的方法是使用then的特殊的两个参数版本,这也避免了需要chai-as-promised

await someAsyncApiCall().then(
  () => { throw new Error('Expected reject') },
  () => {}
)

then方法将在接受时调用第一个lambda,在拒绝时调用第二个lambda。
您可以通过声明自己的函数使其成为泛型。

async function expectReject(promise, message = 'Expected reject') {
  return promise.then(
    () => { throw new Error(message) },
    () => {}
  )
}

然后在你的测试中

it('should reject', async ()=>{
  await expectReject(someAsyncApiCall())
})

相关问题