【问题标题】:Mocha test suite errorring out when attempting to connect to API尝试连接 API 时 Mocha 测试套件出错
【发布时间】:2016-04-06 23:41:41
【问题描述】:

我正在使用mochagulp-jsx-coveragegulp-mocha 运行我的测试套件。我所有的测试都按预期运行并通过/失败。但是,我正在测试的一些模块通过 superagent 库向我的 API 发出 HTTP 请求。

在开发过程中,我还在localhost:3000 与我的客户端应用程序一起运行我的 API,这就是我的客户端测试试图访问的 URL。但是,在测试时,API 通常不会运行。这会在请求通过时导致以下错误:

Error in plugin 'gulp-mocha'
Message:
    connect ECONNREFUSED
Details:
    code: ECONNREFUSED
    errno: ECONNREFUSED
    syscall: connect
    domainEmitter: [object Object]
    domain: [object Object]
    domainThrown: false
Stack:
Error: connect ECONNREFUSED
    at exports._errnoException (util.js:746:11)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:983:19)

我尝试在全局帮助器中对 superagent(别名为 request)库中的所有方法进行存根,如下所示:

function httpStub() {
  return {
    withCredentials: () => {
      return { end: () => {} };
    }
  };
};

beforeEach(function() {
  global.sandbox = sinon.sandbox.create();

  global.getStub = global.sandbox.stub(request, 'get', httpStub);
  global.putStub = global.sandbox.stub(request, 'put', httpStub);
  global.patchStub = global.sandbox.stub(request, 'patch', httpStub);
  global.postStub = global.sandbox.stub(request, 'post', httpStub);
  global.delStub = global.sandbox.stub(request, 'del', httpStub);
});

afterEach(function() {
  global.sandbox.restore();
});

但由于某种原因,当遇到一些测试时,这些方法没有被存根,所以我遇到了ECONNREFUSED 错误。我已经三重检查了,我没有在哪里恢复沙盒或任何存根。

有没有办法解决我遇到的问题,或者有更清洁的解决方案?

【问题讨论】:

  • 行为是确定性的吗?您在写“某些测试”会出现问题 - 是否总是同一组测试失败,或者某个测试可以在一个测试运行中通过而在另一个测试运行中失败?
  • @TomasKulich 它不会每次都在同一个测试中失败,但在某个测试子集中确实会失败。这只是因为这些测试的操作最终会导致对 API 的调用。如果我运行一个先前出错的测试文件,它就会通过。它似乎只在运行整个套件时发生,可能是由于 request 方法以某种方式变得未存根

标签: javascript unit-testing gulp mocha.js


【解决方案1】:

问题可能是由于在您的测试中未正确执行异步操作造成的。想象一下下面的例子:

it('is BAD asynchronous test', () => {
  do_something()
  do_something_else()
  return do_something_async(/* callback */ () => {
    problematic_call()
  })
})

当 Mocha 找到这样的测试时,它会(同步)执行 do_somethingdo_something_elsedo_something_async。在那一刻,从 Mochas 的角度来看,测试结束了,Mocha 为它执行 afterEach() (糟糕的是,problematic_call 仍然没有被调用!)并且(更糟糕的是),它开始运行下一个测试!

现在,显然,以并行方式运行测试(以及 beforeEach 和 afterEach)可能会导致非常奇怪和不可预测的结果,因此出现问题也就不足为奇了(可能 afterEach 在某些测试中间被调用,从而导致 unstubing环境)

如何处理它:

当您的测试结束时,请始终向 Mocha 发出信号。这可以通过返回一个 Promise 对象来完成,或者通过调用 done 回调来完成:

it('is BAD asynchronous test', (done) => {
  do_something()
  do_something_else()
  return do_something_async(/* callback */ () => {
    problematic_call()
    done()
  })
})

https://mochajs.org/

这样 Mocha 会“知道”您的测试何时结束,然后才会运行下一个测试。

【讨论】:

  • 如果这真的是你的问题,你可能仍然很难调试它 - 天哪,我不等待的回调/承诺到底是哪里。如果是这种情况,我会写一些你可以使用的有用技巧。
  • 看来你是对的。我知道异步测试的 done 回调,并认为我在任何必要的地方都使用它,但结果证明我的其他一些测试也需要异步。修复少数损坏的测试也意味着我可以删除request 上那些丑陋的全局存根,并且只删除相关测试中的存根。谢谢!
  • 完美,我很高兴它有帮助。另外,请记住,异步函数的一个很好的选择是返回一个 Promise 对象(不过,您必须正确链接 Promise)。
【解决方案2】:

您的应用程序已经需要request,因此您是否在测试中存根它并不重要。

您需要使用rewire 之类的东西,并将您的应用程序所需的request 替换为您的存根版本。

这样的事情应该会有所帮助

var request = require('superagent'),
    rewire = require('rewire'),
    sinon = require('sinon'),
    application = rewire('your-app'),
    rewiredRequest;

function httpStub() {
    return {
        withCredentials: () => {
            return { end: () => {} };
        }
    };
};

beforeEach(function() {
    var requestStub = {
        get: httpStub,
        put: httpStub,
        patch: httpStub,
        post: httpStub,
        del: httpStub
    };

    // rewiredRequest is a function that will revert the rewiring
    rewiredRequest = application.__set__({
        request: requestStub
    });
});

afterEach(function() {
  rewiredRequest();
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    相关资源
    最近更新 更多