【问题标题】:Catching out-of-scope errors with Mocha and Chai使用 Mocha 和 Chai 捕获超出范围的错误
【发布时间】:2014-12-30 09:37:36
【问题描述】:

我正在修改 node.js 库以支持真正的异步操作。

我在使用 Mocha 和 Chai 时遇到了麻烦,无法通过这个(类似的)测试。

it('should throw an error', function() {
    expect(function() {
        process.nextTick(function() {
            throw new Error('This is my error');
        });
    }).to.throw(Error);
});

问题是 - 由于 nextTick - 错误超出了it 的范围,除了测试失败之外,Mocha 还输出以下内容。

Uncaught Error: This is my error

为了使其成功,构建此测试的正确方法是什么?

【问题讨论】:

    标签: javascript node.js mocha.js chai


    【解决方案1】:

    嗯...在一个成熟的应用程序中,我可能会使用Sinon 之类的东西来检查应该抛出错误的方法是否已被调用并正在抛出。

    在您无法执行此操作的代码中,以下方法将捕获异常:

    var expect = require("chai").expect;
    var domain = require("domain");
    
    it('should throw an error', function(done) {
        var d = domain.create();
        d.on('error', function (err) {
            // Exit the current domain.
            d.exit();
            // We must execute this code at the next tick.
            process.nextTick(function () {
                console.log(err); // Just to show something on the console.
                expect(err instanceof Error).to.be.true;
                done();
            });
        });
    
    
        d.run(function () {
            process.nextTick(function() {
                throw new Error('This is my error');
            });
        });
    });
    

    此代码创建一个"domain",存储在d 中。域将针对其中发生的未捕获异常发出 error 事件,因此我们在我们创建的域 (d.run(...)) 内运行测试并等待异常发生 (d.on('error', ...)。我们检查它是否是一个Error 对象。 (在实际测试中,我还会检查错误消息。)当我们完成后,我们调用done() 告诉 Mocha 异步测试已经结束。

    error 事件的处理程序调用d.exit()。这是为了让 Mocha 在断言 (expect(err instanceof Error)...) 失败时可以正常捕获错误。如果我们不退出域,那么域将捕获错误。此外,检查本身必须在下一个报价时执行,以超出 d 域。

    使用domain 有问题吗?

    不!

    domain 的文档附带了一些警告,即一旦在运行正在进行的进程(如服务器)时捕获到未捕获的异常,就会关闭操作。那么要做的就是把能清理的东西清理干净,尽快退出。 但是,在测试中使用 domain 与 Mocha 已经在做的没有什么不同。 Mocha 在异步代码中捕获未处理异常的方式是使用 process.on('uncaughtException'。在捕获未处理的异常 Mocha marks 时,当前测试失败并继续。然而,关于uncaughtExceptiondocumentation 却说“不要使用它,改用domains。如果您确实使用它,请在每次未处理的异常后重新启动您的应用程序!”

    所以,任何在使用 domain 时遇到问题的人都不应首先使用 Mocha

    【讨论】:

    • 我认为这就是我正在寻找的答案。非常感谢。 :)
    • 你应该看看这个:joyent.com/developers/node/design/errors 看到这个引用“域和进程范围的 'uncaughtException' 事件主要用于尝试处理意外的程序员错误或从意外的程序员错误中恢复。出于所有描述的原因以上,强烈建议不要这样做。”
    • @eshortie 您必须更具体地了解使用域可能导致的问题。正如我在回答中所说,我已将域用于脚本类型代码而没有任何不良影响。如果这意味着要在必须无限期地继续运行的进程中使用,那将是另一回事。
    • 域已弃用,应避免使用。 nodejs.org/api/domain.html#domain_domain
    • @Esteban 您链接到的文档明确声明“此模块弃用。一旦替换 API 完成,该模块将被完全弃用。”它正在被弃用,但还没有。正如我们所说,除了使用域来做 OP 想做的事情之外,别无选择。在他们生成备用 API 之前,我会保留反对票。
    【解决方案2】:

    您正试图在不正确的函数上捕获异常,即抛出函数的容器。另外,由于该函数被包装在 nextTick 中,它在不同的堆栈中执行,因此无法捕获异常(不幸的是,这只是一个 JS 的事情)。

    试试这个:

    it ('should throw an error', function (done) {
    
      process.nextTick(function () {
        var myFn = function () { throw new Error() };
    
        expect(myFn).to.throw(Error);
    
        // Tell mocha the test is complete 
        done();
      });
    });
    

    更新:没有适当的方法来构建此测试以使其通过,因为在这种情况下您无法捕获异常。也许更新您的代码以使用回调来处理错误:

    function doSomethingUnsafe() {
    
      try {
        // Run code here that may cause exceptions...
        callback(null, 'Woohoo! No errors!');
      } catch (e) {
        callback (e, null);
      }
    }
    

    【讨论】:

    • 问题并不明显,但它有点复杂。 nextTick 是在我正在测试的函数中完成的,所以我无法像那样切换东西......
    • 您不能按照通常的 Node.js 约定,通过 try/catch 使用回调来处理错误吗?还是 Louis 解释的域?
    猜你喜欢
    • 2014-03-02
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    相关资源
    最近更新 更多