【问题标题】:Why does mocha timeout when used with restify and knex?为什么 mocha 与 restify 和 knex 一起使用时会超时?
【发布时间】:2017-01-02 08:52:26
【问题描述】:

我目前正在使用 mocha 2.5.3、supertest 2.0.0、knex 0.11.10、restify 4.1.1 和 sqlite3 3.1.4。

我有以下非常简单的 restify 服务器:

const restify = require('restify');
const knex = require('knex')({
  client: 'sqlite3',
  connection: {
    'filename': 'test.db'
  }
});

const app = restify.createServer();

app.get('/', (req, res, next) => {
  knex.select().from('nonexistent_table')
  .then((rows) => {
    return res.json(rows);
  })
  .catch((err) => {
    return res.send('error');
  });
});
module.exports = app;

以下测试将导致测试在 2000 毫秒超时而不是失败:

const assert = require('assert');
const supertest = require('supertest');
const app = require('./app');

describe('GET /', function () {

  it('should not timeout', function (done) {
    supertest(app)
    .get('/')
    .end(function(err, res) {
      assert(false);
      done();
    });
  });
});

如果对 knex 的调用得到满足而不是被拒绝,则测试会正确失败并且不会超时。仅当拒绝 knex 调用时才会出现超时。

有没有人想过什么可能导致超时而不是正确的失败?

编辑:我已经尽可能地调试了这个,似乎超时发生在 mocha 尝试生成堆栈跟踪时。

【问题讨论】:

  • 查看我的答案here:因为断言引发了错误,所以永远不会调用done并且永远不会捕获错误。
  • @robertklep 谢谢,但我不确定这是正确的答案,原因有两个。首先,如果 knex 解析,则测试正常失败。由于我在测试中直接使用assert(false),因此故障模式完全不应该取决于来自restify服务器的响应或来自knex的结果,但它确实如此!其次,如果我编写了一个不执行异步 http 调用的 mocha 测试并简单地抛出一个错误,那么即使我从未调用过 done(),测试也会正确地失败并且不会超时。这让我相信抛出错误/失败断言是 mocha 测试失败的正常方式。

标签: node.js mocha.js restify supertest


【解决方案1】:

尝试将第一行更改为: bluebird.resolve(knex.select().from('nonexistent_table'))

您还需要在顶部添加“bluebird”。它将解决问题并为您提供有关错误的一些上下文

我认为 select 的问题:你忘记了一个参数

【讨论】:

  • 刚刚尝试了这两种可能的解决方案,但都没有解决问题。即,我尝试了knex.select('*').from('nonexistent_table'),也尝试了bluebird.resolve(knex.select('*')from('nonexistent_table'))
【解决方案2】:

supertest 在幕后使用superagentsuperagent 支持承诺。 (搜索.thenhere。)所以你可以使用.then而不是.end并且只返回promise而不是使用done

  it('should not timeout', function () {
      return supertest(app)
          .get('/')
          .then(function(res) {
              assert(false);
          });
  });

当我将上面的代码与问题中的其余代码一起使用时,我会遇到正确的失败。

至于为什么使用done 不起作用,我不清楚。 supertestsuperagent 可能会吞下在传递给 .end() 的回调中引发的异常。如果异常被吞下,那么 Mocha 就无法检测到它们。然后,您必须自己捕获由失败的断言引发的异常并将它们传递给done。我更喜欢使用 Promise。

【讨论】:

  • 我的猜测是,在失败的情况下,end 回调是从 inside 路由处理程序中的 .catch() 调用的,这将吞下断言错误 并且防止done被调用。
  • 我同意承诺可能是正确的方向。但是我开始认为这可能是节点中的错误,因为如果我在.end() 回调中引发异常,但未在服务器端调用 knex,则测试通常会失败。这对我来说,superagent 没有吞下异常。这里发生了其他事情,我认为这与 mocha 的堆栈跟踪生成有关。我会用我的发现更新我的问题。
  • 另一种理论是,由于catch 没有发送错误响应,一些内部superagent 承诺可能会得到解决,因此随后的断言失败不能再拒绝它。
  • @robertklep 我想你可能在这里有所收获。我尝试将 restify 换成 express 并且它工作得很好,这对我来说是 restify 与 superagent 交互的方式导致异常卡在.catch() 路由中。也许这是 restify 中的一个错误。
  • @harrymonster 是的,我正要发布同样的内容,Express 按预期工作 =D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-28
  • 1970-01-01
  • 2012-10-17
  • 2017-06-24
  • 2021-08-01
  • 1970-01-01
相关资源
最近更新 更多