【问题标题】:Testing Express errors with Mocha and Supertest使用 Mocha 和 Supertest 测试 Express 错误
【发布时间】:2016-06-05 20:57:04
【问题描述】:

例如,我必须在不能(或不应该)随响应一起发送的验收测试中测试服务器错误(Express)

错误:发送后无法设置标头。

使用错误处理程序捕获错误并使用 5XX 代码响应将在此处提供有价值的反馈,但问题是标头已经发送。

这类错误可能不重要且难以发现,通常可以从日志中发现。

规格是

it('should send 200', function (done) {
    request(app).get('/').expect(200, done);
});

测试的应用是

app.get('/', function (req, res, next) {
    res.sendStatus(200);
    next();
});

app.use(function (req, res) {
    res.sendStatus(200);
});

在类似情况下,Express app 实例和请求测试库(即 Supertest)之间最合适的通信方式是什么?

问题不仅限于 Supertest。如果有包能解决超测不能解决的问题,也可以考虑。

【问题讨论】:

  • res.status(500).send()怎么样
  • @WalkerRandolphSmith 第一个 res.sendStatus 已经发送了标头,这将导致另一个“发送后无法设置标头”错误。
  • 啊,我想我现在明白了。
  • 我没有收到 Can't set headers after they are sent 错误。
  • @KlwntSingh 当然。问题是如何在测试中发现这类问题。您需要了解问题才能解决问题。

标签: node.js express testing mocha.js supertest


【解决方案1】:

尽量只设置状态码而不发送,避免发送两次抛出错误使用res.status()。

正如express documentation 所说的那样

设置响应的 HTTP 状态。它是 chainable 的别名 节点的response.statusCode。

恕我直言,如果您想在 end-to-end (E2E) 测试工具(如 supertest(或 Selenium)中检测 ) 你必须处理 express 错误并发送正确的输出(500 状态错误,一些消息......)以允许检测它。

或者改用unit test,以测试控制器函数不会使用chai 或本机断言引发任何错误。

【讨论】:

  • 因此不会发送响应。问题的重点是检测错误,而不是修改应用代码。
  • 谢谢。关于 500 错误,问题还是一样——一旦发送了 200 响应,就不能将其更改为 500。并且单元测试应该与其他单元隔离执行。这意味着测试可能会通过特定的中间件,但当多个中间件堆叠时会导致错误。
  • 是的,它破坏了中间件链,您只需检查最终输出是否与您预期的不一样。
【解决方案2】:

我回答了一个类似的问题here。 “设置标头后无法设置标头”错误应由 express 引发为未处理的异常。因此,您应该能够通过进程引发的 unhandledException 事件来访问它。

但是,由于时间关系,这要复杂得多。在第一次 res.statusCode 调用之后,您的测试用例的 expect 函数和 done 函数将在事件循环上排队等待处理。不幸的是,对 res.statusCode 的下一次调用可能会在之后的不确定时间发生。例如,如果第二个路由处理程序调用一个非常慢的 web 服务或 db,然后调用 res.statusCode。

考虑到这一点,您的选择非常困难。蛮力方法是在您的测试代码中等待一段确定的时间,然后进行检查。它有效但缓慢且不确定,这将导致您的测试不稳定。

另一种选择是检查您在 express 中可能拥有的任何检测代码。如果您的 express 代码保留了各种路由处理程序的进程调用数量的指标,您可以将这些指标公开给您的测试代码。然后,完成测试的条件之一是进程中路由调用的所有指标均为 0。第二个选项将允许您编写确定性测试并且速度更快,因为您可以轮询指标。

最后的选择是通过单元测试来处理这个测试用例。这可能是最好的解决方案,因为它是确定性的并且不需要任何形式的轮询。然而,缺点是你需要知道你的两个函数都是按顺序调用的,这会导致你尝试在测试代码中重新创建 express 用于调用路由处理程序的逻辑。

【讨论】:

    【解决方案3】:

    我使用 HAPI 而不是 Express 来完成此操作,但我解决了同样的问题。我使用外部库进行调用(如 request-promise)并且它有效。在 request-promise 响应中捕获错误。

    【讨论】:

    • 我不确定你的意思。在示例中 request-promise 无法捕获错误,因为响应本身没有错误 - 它是 200。请参阅 cmets,这已经在那里讨论过。
    猜你喜欢
    • 1970-01-01
    • 2013-01-23
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    相关资源
    最近更新 更多