Node.js assert.throws 具有异步功能(承诺)

Node.js assert.throws with async functions (Promises)

我想使用本机 assert 模块中的 assert.throws 检查异步函数是否抛出异常。 我试过

const test = async () => await aPromise();
assert.throws(test); // AssertionError: Missing expected exception..

它(显然?)不起作用,因为该函数在 Promise 解析之前就退出了。 然而我发现 this question 使用回调可以达到同样的效果。

有什么建议吗?

(我正在使用 Babel 转译为 Node.js 本机生成器。)

节点 10 和更新的节点

从 Node.js v10.0 开始,assert.rejects 就是这样做的。

旧版本的节点

async 函数从不抛出 - 它们 return 承诺可能会被拒绝。

您不能对它们使用 assert.throws您需要编写自己的异步断言:

async function assertThrowsAsynchronously(test, error) {
    try {
        await test();
    } catch(e) {
        if (!error || e instanceof error)
            return "everything is fine";
    }
    throw new AssertionError("Missing rejection" + (error ? " with "+error.name : ""));
}

并像

一样使用它
return assertThrowsAsynchronously(aPromise);

在异步测试用例中。

基于 I've suggest more universal solution that utilizes original assert.throws 的错误消息:

import assert from 'assert';

async function assertThrowsAsync(fn, regExp) {
  let f = () => {};
  try {
    await fn();
  } catch(e) {
    f = () => {throw e};
  } finally {
    assert.throws(f, regExp);
  }
}

用法:

it('should throw', async function () {
    await assertThrowsAsync(async () => await asyncTask(), /Error/);
});

给出的答案有效,但我今天遇到了这个问题并提出了另一个解决方案,我认为它更简单一些。

// Code being tested
async function thisFunctionThrows() {
    throw new Error('Bad response')
}


// In your test.
try {
    await thisFunctionThrows()
    assert.equal(1 == 0) // Never gets run. But if it does you know it didn't throw.
} catch (e) {
    assert(e.message.includes('Bad response'))
}

您将要使用 assert.rejects(),这是 Node.js 版本 10 中的新功能。

在高层次上,我们想要 assert.rejects 之类的东西,而不是 assert.throws,希望你能接受这个和 运行:

        const assertRejects = (fn, options) => {
            return Promise.resolve(fn()).catch(e => {
                    return {
                        exception: e,
                        result: 'OK'
                    }
                })
                .then(v => {

                    if (!(v && v.result === 'OK')) {
                        return Promise.reject('Missing exception.');
                    }

                    if (!options) {
                        return;
                    }

                    if (options.message) {
                        // check options
                    }

                    console.log('here we check options');

                });
        };

        it('should save with error', async () => {

            // should be an error because of duplication of unique document (see indexes in the model)
            return await assertRejects(async () => {

                patientSubscriber = await PatientSubscriber.create({
                    isSubscribed: true,
                    patient: patient._id,
                    subscriber: user._id
                });

            }, {
                message: /PatientSubscriber validation failed/
            });

        });

由于问题还在关注中,我想总结一下两个最好的解决方案,特别强调一下新的标准方法。

节点 v10+

断言库中有一个专用方法,assert.rejects

对于旧版本的 Node

来自 的填充:

import assert from 'assert';

async function assertThrowsAsync(fn, regExp) {
  let f = () => {};
  try {
    await fn();
  } catch(e) {
    f = () => {throw e};
  } finally {
    assert.throws(f, regExp);
  }
}