如何测试摩卡中未捕获的错误

How can I test uncaught errors in mocha?

本文关键字:错误 摩卡 何测试 测试      更新时间:2023-09-26

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

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();
        });
    });
});

但摩卡似乎想把任何错误都保密,当它出现错误时,我的测试就会失败:

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)

有什么想法吗?

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

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


老答案:

秘密在于过程。listeners('uncaughtException'):

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

只需移除摩卡监听器,添加您自己的,然后重新连接摩卡监听器。

见下文:

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()
        })
    })
})

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

为此,您可以使用:

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();
    });
});

作为选项在测试中指出mocha.options.allowUncaught=true在try{}catch()中,mocha中不会捕获错误确保mocha对象存在于测试中。

但在这种情况下,如果mocha中没有发现错误,那么其余的测试将失败。在mocha中禁用try{}catch(){}只有在调试时才有用。

基于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()
    })
})