Node.js assert.throws 带有异步函数(Promises)

Posted

技术标签:

【中文标题】Node.js assert.throws 带有异步函数(Promises)【英文标题】:Node.js assert.throws with async functions (Promises) 【发布时间】:2016-06-17 09:13:46 【问题描述】:

我想检查是否使用原生 assert 模块中的 assert.throws 引发了异步函数。 我试过了

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

它(显然?)不起作用,因为函数在 Promise 解决之前退出。 然而我发现this question 使用回调实现了同样的事情。

有什么建议吗?

(我正在使用 Babel 转换为 Node.js 原生生成器。)

【问题讨论】:

【参考方案1】:

节点 10 和更新的节点

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

旧版本节点

async 函数从不抛出 - 它们返回可能被拒绝的承诺。

您不能对它们使用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);

在异步测试用例中。

【讨论】:

这是不必要的,因为assert.throws 已经返回了一个行为与此完全相同的承诺 @Ali 您在使用哪个assert.throws? native node.js one 既不返回承诺,也不处理返回承诺的函数 这是原生的。至少在节点 v8 中。它没有记录在案,但这就是它正在做的事情。 @Ali No, it doesn't? 是的,它没有。对困惑感到抱歉。我们正在使用来自npmassert-throws-async 并替换本机assert.throws。我错过了它,因为原始文件已替换为不同的文件,并且无需在我的文件中重新导入 assert-throws-async 即可工作。【参考方案2】:

基于Bergi answer,我建议使用原始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/);
);

【讨论】:

优秀的解决方案,希望能成为官方断言库! 你是我的英雄! 是的,不要在 2018 年及以后使用这个,使用 assert.rejects(),这里:nodejs.org/api/…【参考方案3】:

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

// 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'))

【讨论】:

由于我使用的是较早版本的 Node ( 【参考方案4】:

由于这个问题仍然受到关注,我想总结两个最佳解决方案,特别是强调新的标准方法。

节点 v10+

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

对于旧版本的 Node

来自vitalets answer的填充:

import assert from 'assert';

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

【讨论】:

【参考方案5】:

您将要使用 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/
            );

        );

【讨论】:

以上是关于Node.js assert.throws 带有异步函数(Promises)的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 Javascript 的 MySQL (node.js)

Node.js 永远带有环境变量

带有 Express 异步 API 调用的 Node.JS

node.js - 带有 base64 的 http [重复]

服务器和客户端上带有 Handlebars.js 的 Node.js

node.js 在间隔中迭代数组特定时间