无法从超级应用请求中捕获异常

时间:2013-12-24 22:22:02

标签: javascript node.js testing mocha supertest

此处显示的代码示例:https://gist.github.com/sebinsua/8118001

(有三次失败和两次传球。我希望有四次失败,一次失败。)

如果从正常函数抛出,可以使用mocha捕获AssertionErrors,但是一旦从超级包装应用程序中调用函数,我就无法再检测到它们。这很烦人,因为我想能够将某些断言注入我的快速应用程序,然后我可以测试。 (我正在测试一个带有我希望测试的副作用的中间件,如果你能告诉我如何模拟请求和响应对象,这也解决了我的问题。)

因为我能够访问间谍,所以我知道这与无法访问的状态无关。

但是,我注意到node.js / express.js / supertest会自动将未捕获的异常转换为响应中的错误消息。也许这就是阻止他们被摩卡测试所困扰的原因?

修改

我刚刚测试了下面的代码,看看这是否是一般的http.createServer()问题。事实并非如此。这意味着在connect,express.js,supertest或superagent级别发生了一些事情。 (这些代码片段只能用于半个小时的btw ...)

var http   = require("http"),
    assert = require('assert');

describe('Really crazy test of assertions', function () {
    it("cannot create a server which throws an assertion error", function (done) {
        var port = Math.floor(Math.random() * 9999) + 1;
        http.createServer(function (req, res) {
            console.log("On the server.");
            throw new assert.AssertionError({ message: "Can I throw an assertion error? "} );
            res.end("HEY");
        }).listen(port);

        setTimeout(function () {
            console.log("On the client.");
            http.get('http://localhost:' + port + '/', function (res) {
                console.log("Will I receive the error message on the client's side? No.");
                console.log(res);
            });
            done();
        }, 1000);
    });
});

它看起来像一个明确的问题(见下文) - 我注意到AssertionError没有出现在红色文本中(就像被Mocha拾取一样)。

var http    = require("http"),
    express = require("express"),
    assert  = require('assert');

var app = express();

describe('Really crazy test of assertions', function () {

    it("cannot create a server which throws an assertion error", function (done) {
        var port = Math.floor(Math.random() * 9999) + 1;
        app.get('/', function (req, res) {
            console.log("On the server.");
            throw new assert.AssertionError({ message: "Can I throw an assertion error? "} );
            res.end('HEY');
        }).listen(port);

        setTimeout(function () {
            console.log("On the client.");
            http.get('http://localhost:' + port + '/', function (res) {
                console.log("Will I receive the error message on the client's side? No.");
                console.log(res);
            });
            done();
        }, 1000);
    });
});

简而言之,我的问题是,我如何让A表现得像B?

A

var http    = require("http"),
    express = require("express"),
    assert  = require('assert');

var app = express();

var port = Math.floor(Math.random() * 9999) + 1;
app.get('/', function (req, res) {
    console.log("On the server.");
    throw new assert.AssertionError({ message: "Can I throw an assertion error? "} );
    res.send('HEY');
}).listen(8888);

var http   = require("http"),
    assert = require('assert');

http.createServer(function (req, res) {
    console.log("On the server.");
    throw new assert.AssertionError({ message: "Can I throw an assertion error? "} );
    res.end("HEY");
}).listen(8888);

更新

senchalab在/lib/proto.js上连接的第192行是出错的地方。有一个try-catch,这将我的错误传递给下一个中间件,它继续做同样的事情,直到4-arity中间件处理它或没有更多的中间件,它运行一些后备代码自动打印到屏幕并放弃例外......

我不知道我能做些什么来让它再次抛出我的错误,除非我能够覆盖句柄方法或其他方法。

1 个答案:

答案 0 :(得分:1)

你问:

  

但是,我注意到node.js / express.js / supertest会自动将未捕获的异常转换为响应中的错误消息。也许这就是阻止他们被摩卡测试所困扰的原因?

是的,这几乎是HTTP服务器默认工作的方式:对服务器软件没有任何特殊含义的异常将转换为状态500响应。因此,如果您想测试服务器是否抛出了异常,您可以自己记录这个事实并在以后使用它。例如:

var http    = require("http"),
    express = require("express"),
    assert  = require('assert');

var app = express();

function handler (req, res) {
    throw new assert.AssertionError({ message: "Can I throw an assertion error? "} );
    res.end('HEY');
}

describe('Really crazy test of assertions', function () {
    it("cannot create a server which throws an assertion error", function (done) {
        var port = Math.floor(Math.random() * 9999) + 1;
        var caught;
        app.get('/', function catcher() {
            try {
                handler.apply(this, arguments);
            }
            catch (ex) {
                caught = ex;  // Capture it ...
                throw ex;     // ... and rethrow it.
            }
        }).listen(port);

        setTimeout(function () {
            http.get('http://localhost:' + port + '/', function (res) {
                // Act on the caught exception, if it exists.
                // This could be assert.equal or whatever.
                if (caught)
                    throw caught;
                done();
            });
        }, 1000);
    });
});

这是为了说明原理。 catcher函数可以设计得足够通用,可以用于一大堆不同的测试。