在摩卡测试中,调用异步函数时如何避免超时错误:超过2000ms的超时


200

在我的节点应用程序中,我正在使用mocha测试我的代码。使用mocha调用许多异步函数时,出现超时错误(Error: timeout of 2000ms exceeded.)。我该如何解决?

var module = require('../lib/myModule');
var should = require('chai').should();

describe('Testing Module', function() {

    it('Save Data', function(done) {

        this.timeout(15000);

        var data = {
            a: 'aa',
            b: 'bb'
        };

        module.save(data, function(err, res) {
            should.not.exist(err);
            done();
        });

    });


    it('Get Data By Id', function(done) {

        var id = "28ca9";

        module.get(id, function(err, res) {

            console.log(res);
            should.not.exist(err);
            done();
        });

    });

});

是集成测试吗?运行测试需要很多时间-也许您应该考虑存根-github.com/thlorenz/proxyquire可能会对您有所帮助。
surui

@surui谢谢,我会关注一下
sachin

我可以建议对异步内容使用诺言并对其进行测试,然后与Chai一起做诺言
Krym 2015年

Answers:


344

您可以在运行测试时设置超时:

mocha --timeout 15000

或者,您可以通过编程为每个套件或每个测试设置超时:

describe('...', function(){
  this.timeout(15000);

  it('...', function(done){
    this.timeout(15000);
    setTimeout(done, 15000);
  });
});

有关更多信息,请参阅文档


3
较短的版本是-t。如果您使用mocha-test从grunt任务运行mocha,则options对象也支持此功能options:{timeout:15000}
svassr 2014年

5
仅供参考:不建议将箭头函数传递给摩卡。mochajs.org/#arrow-functions
凌晨

4
在上面的链接中不建议使用箭头功能。它只是说您只需要知道它们的操作,因此在访问上下文时不必费心。我从来不需要上下文,因为依赖超时非常脆弱,我的所有测试都在几毫秒内运行,但是在使用sinon-test时确实遇到了相同的问题。仍然有99%的时间使用lambda。
oligofren

26
TypeError: this.timeout is not a function使用时"mocha": "^3.5.0"
JuniorMayhé2017年

5
@adi您确定不使用箭头功能吗?关于异步/等待它在文档中,因此应该可以工作(和使用promise是一样的事情)。听起来像是另一个问题。
安德烈亚斯(Andreas Hultgren)

80

我发现仅增加超时的“解决方案”就掩盖了这里真正发生的事情,

  1. 您的代码和/或网络调用太慢(为了获得良好的用户体验,应少于100毫秒)
  2. 断言(测试)失败,并且某些东西吞没了错误,然后Mocha可以对它们采取行动。

当Mocha没有收到来自回调的断言错误时,您通常会遇到#2。这是由于其他一些代码将异常吞没到堆栈的上方而导致的。解决此问题的正确方法是修复代码,不要吞下错误

当外部代码吞噬您的错误时

如果这是您无法修改的库函数,则需要捕获断言错误并将其自己传递给Mocha。为此,您可以将断言回调包装在try / catch块中,然后将所有异常传递给done处理程序。

it('should not fail', function (done) { // Pass reference here!

  i_swallow_errors(function (err, result) {
    try { // boilerplate to be able to get the assert failures
      assert.ok(true);
      assert.equal(result, 'bar');
      done();
    } catch (error) {
      done(error);
    }
  });
});

当然可以将此样板提取到一些实用程序功能中,以使测试更加令人愉悦:

it('should not fail', function (done) { // Pass reference here!
    i_swallow_errors(handleError(done, function (err, result) {
        assert.equal(result, 'bar');
    }));
});

// reusable boilerplate to be able to get the assert failures
function handleError(done, fn) {
    try { 
        fn();
        done();
    } catch (error) {
        done(error);
    }
}

加快网络测试

除此之外,我建议您采纳有关开始使用测试存根进行网络调用以使测试通过而不必依赖于运行正常的网络的建议。使用Mocha,Chai和Sinon,测试可能看起来像这样

describe('api tests normally involving network calls', function() {

    beforeEach: function () {
        this.xhr = sinon.useFakeXMLHttpRequest();
        var requests = this.requests = [];

        this.xhr.onCreate = function (xhr) {
            requests.push(xhr);
        };
    },

    afterEach: function () {
        this.xhr.restore();
    }


    it("should fetch comments from server", function () {
        var callback = sinon.spy();
        myLib.getCommentsFor("/some/article", callback);
        assertEquals(1, this.requests.length);

        this.requests[0].respond(200, { "Content-Type": "application/json" },
                                 '[{ "id": 12, "comment": "Hey there" }]');
        expect(callback.calledWith([{ id: 12, comment: "Hey there" }])).to.be.true;
    });

});

有关更多信息,请参见Sinon的nise文档


我有大量的测试套件,我只是通过了规范中的所有promise,以确保它们都done()在promise的末尾进行调用,并且我已经在使用Angular的网络调用进行了模拟$httpBackend,但是没有运气。用try-catch包装每个规范似乎并不实用。还有其他建议吗?谢谢!
古斯塔沃·马蒂亚斯

@GustavoMatias您实际上并没有提到您的问题所在,只是说这不是解决您遇到的任何问题的方法。请详细说明:-)您的测试失败是否足够快?它们有时会失败,但是您想知道为什么吗?很难猜到您打算实现什么。
oligofren

嗨@oligofren!这确实不是最好的解释。这里有我的问题的更详细的解释stackoverflow.com/questions/34510048/…谢谢!
古斯塔沃·马蒂亚斯

“通常,处理此问题的最简洁的方法(但最丑陋的方法)是使用try / catch包装代码并将所有异常传递给完成的处理程序。” 不,这根本不是最干净的方法。不是由一个长镜头。最干净的方法是编写不会吞下异常的代码。每当我看到有人抱怨Mocha没检测到失败的测试时,那是因为有些东西吞没了异常。添加一个try.... catch...作品围绕在被测代码的bug,而不是修复它。
路易

@Louis,您可能对这里的问题是正确的,但是我无法立即对其进行验证。无论如何,人们似乎有一个问题,那就是Mocha 似乎无法捕获某些错误,这是一种处理错误的方法。您给定的方法假定吞没该错误的代码不是某些库函数或类似函数,在这种情况下,将不那么容易解决。
oligofren

7

有点晚了,但是将来有人可以使用...您可以通过以下方法更新package.json中的脚本来增加测试超时:

"scripts": { "test": "test --timeout 10000" //Adjust to a value you need }

使用以下命令运行测试 test


为我工作!谢谢!
RayLoveless

5

如果使用箭头功能:

it('should do something', async () => {
  // do your testing
}).timeout(15000)

1

对我来说,问题实际上是describe函数,当提供箭头函数时,mocha会错过超时,并且行为不一致。(使用ES6)

因为没有承诺被拒绝,我一直在描述块内失败的不同测试中始终遇到此错误

因此,在无法正常工作时的外观如下:

describe('test', () => { 
 assert(...)
})

这可以使用匿名功能

describe('test', function() { 
 assert(...)
})

希望对我的配置有所帮助(nodejs:8.4.0,npm:5.3.0,mocha:3.3.0)


0

我的问题是没有发送回响应,所以它挂了。如果您使用Express,请确保对要测试的路由执行了res.send(data),res.json(data)或您想使用的任何api方法。


0

确保解决/拒绝测试用例中使用的承诺,无论是间谍还是存根,都要确保它们解决/拒绝。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.