【问题标题】:How can I test uncaught errors in mocha?如何在 mocha 中测试未捕获的错误?
【发布时间】:2012-02-19 22:59:52
【问题描述】:

我想测试以下函数是否按预期执行:

function throwNextTick(error) {
    process.nextTick(function () {
        throw error;
    });
}

这是我的尝试:

describe("throwNextTick", function () {
    it("works as expected", function (next) {
        var error = new Error("boo!");
        var recordedError = null;
        process.once("uncaughtException", function (error) {
            recordedError = error;
        });

        throwNextTick(error);

        process.nextTick(function () {
            recordedError.should.be(error);
            next();
        });
    });
});

但 mocha 似乎想将任何错误留给自己,并在得到它们时使我的测试失败:

C:\Users\ddenicola\Programming (Synced)\pubit>mocha test/basicTest.js

  throwNextTick
    0) works as expected

  ? 1 of 1 tests failed:

  1) throwNextTick works as expected:
     Error: boo!
      at Test.fn (C:\Users\ddenicola\Programming (Synced)\pubit\test\basicTest.js:11:21)
      at Test.run (C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:144:15)
      at Runner.runTest (C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:271:10)
      at C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:315:12
      at next (C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:199:14)
      at C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:208:7
      at next (C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:157:23)
      at Array.0 (C:\Users\ddenicola\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:176:5)
      at EventEmitter._tickCallback (node.js:192:40)

有什么想法吗?

【问题讨论】:

    标签: javascript unit-testing exception node.js mocha.js


    【解决方案1】:

    基于 timoxley 和 Casey Foster,在节点 v6++ 中

    const assert = require('assert')
    
    describe('throwNextTick', function() {
        it('works as expected', function(next) {
    
            function cb(err) {
                assert.equal(err instanceof Error, true)
                next()
            }
    
            function test(){
                process.nextTick(() => {
                    throw new Error('err')
                })
            }
    
            process.prependOnceListener('uncaughtException', cb)
            test()
    
        })
    })
    

    【讨论】:

    • 你总是可以用 --require babel-core/register 运行 mocha 来获得 import/export 并添加 .babelrc 和 {"presets": ["es2015"]}
    【解决方案2】:

    更新:由 casey-foster 在下面的评论中提供:

    从节点 v6.0.0 开始,您可以使用 process.prependOnceListener('uncaughtException', ...) 更简洁地执行此操作。


    旧答案:

    秘密在于 process.listeners('uncaughtException'):

    http://nodejs.org/docs/latest/api/events.html#emitter.listeners

    只需移除 mocha 侦听器,添加您自己的侦听器,然后重新附加 mocha 侦听器。

    见下文:

    var assert = require('assert')
    
    function throwNextTick(error) {
        process.nextTick(function () {
            throw error
        })
    }
    
    
    describe("throwNextTick", function () {
        it("works as expected", function (next) {
            var error = new Error("boo!")
            var recordedError = null
            var originalException = process.listeners('uncaughtException').pop()
            //Needed in node 0.10.5+
            process.removeListener('uncaughtException', originalException);
            process.once("uncaughtException", function (error) {
                recordedError = error
            })
            throwNextTick(error);
            process.nextTick(function () {
                process.listeners('uncaughtException').push(originalException)
                assert.equal(recordedError, error)
                next()
            })
        })
    })
    

    【讨论】:

    • 这成功了!我只会对您的答案进行一次编辑:您需要在执行断言之前恢复原始侦听器,因为断言会引发错误。
    • 这真的应该在 Mocha 的文档中!我花了一个小时在谷歌上搜索才找到这个答案。 Mocha 对错误(和失败的测试)的无证捕获,再加上如果你没有抛出标准的 Error 对象(根据 Crockford 的建议)不会显示错误消息的事实,使得很难弄清楚测试失败的原因。
    • 似乎在最新版本的节点中(在此评论时为 v0.10.5)process.listeners(eventName) 返回了侦听器数组的副本,因此实际上不会调用pop()从发射器中移除听者。您需要在弹出后添加以下行:process.removeListener('uncaughtException', originalException);
    • 由于 process.listeners(eventName) 在最后返回一个副本,而不是 push,因此您需要将其添加回来。
    • node v6.0.0 开始,您可以使用process.prependOnceListener('uncaughtException', ...) 更简洁地执行此操作。
    【解决方案3】:

    如果您的异步代码在域内执行 - 通常是这种情况 - 您需要更改域上的错误侦听器而不是进程。

    为此,您可以使用:

    it('should produce an unhandled exception', function (done) {
    
        // Remove Mocha's error listener
        var originalErrorListeners = process.domain.listeners('error');
        process.domain.removeAllListeners('error');
    
        // Add your own error listener to check for unhandled exceptions
        process.domain.on('error', function () {
    
            // Add the original error listeners again
            process.domain.removeAllListeners('error');
            for ( var i = 0; i < originalErrorListeners.length; i+=1 ) {
                process.domain.on('error', originalErrorListeners[i]);
            }
    
            // For the sake of simplicity we are done after catching the unhandled exception
            done();
    
        });
    
        // This would be your async application code you expect to throw an exception
        setTimeout(function () {
            throw new Error();
        });
    
    });
    

    【讨论】:

      猜你喜欢
      • 2018-05-10
      • 2017-07-02
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      • 2015-07-10
      • 2021-09-19
      • 2019-10-11
      • 1970-01-01
      相关资源
      最近更新 更多