无论如何都超过了摩卡超时

Posted

技术标签:

【中文标题】无论如何都超过了摩卡超时【英文标题】:Mocha timeout exceeded no matter what 【发布时间】:2015-04-30 16:59:45 【问题描述】:

我目前正在用 mocha 为我的 nodejs 应用程序编写测试。我的 api 调用要求我登录,所以我想创建一个包装测试套件,它创建一个测试用户,然后调用实际的测试套件。下面是代码的样子:

var request = require('supertest');

var config = require('../config/config');

var AdminUser = require('../models/Authmodel');



function configureAuth(test_suite) 
    var url = "localhost:" + config.port;

    var email = "test@test.com";
    var password = "test_password";

    var admin;
    var token;

    describe("Signup User", function() 
      it("should signup new user", function(done) 
        request(url)
          .post('/auth/signup')
          .send(
            email: email,
            password: password
          )
          .expect(200)
          .end(function()
            done();
          );
      );

      it("should login the user", function(done) 
        request(url)
          .post('/auth/login')
          .send(
            email: email,
            password: password
          )
          .expect(200)
          .end(function(err,res)
            if(err)
              throw(err);
            res.body.should.have.property('token');
            token = res.body.token;
            done();
          );
      );

      it("should retrieve admin document", function(done) 
        AdminUser.findOne(email: email, function(err, dbAdmin) 
          if(err)
            throw(err);
          admin = dbAdmin;
          done();
        );
      );
    );

    // Call the actual test suite, pass it the auth credentials.
    describe("Test Suite", function() 
        it("should run the test suite", function(done) 
            // No matter what the timeout is set to it still exceeds it
            this.timeout(5000);
            test_suite(
                email: email,
                password: password,
                token: token,
                admin: admin
            , done);
        );
    );

    describe("Clear Admins", function() 
    it("should clear the admin table", function(done) 
      AdminUser.remove(email: email, function(err) 
        if(err)
          throw(err);

        done();
      );
    );
  );

;

module.exports = configureAuth;

这是一个使用包装器的测试套件:

var request = require('supertest');

var config = require('../config/config');

// Wrapper that creates admin user to allow api calls
var ConfigureAuth = require('./ConfigureAuth');


// Test data
var templateForm = ...
var submittedForm = ...

ConfigureAuth(
  function(credentials, exit) 

    var url = "localhost:" + config.port;

    var templateFormId = null;
    describe("Form Templates", function() 
      describe('POST /api/form/template', function()
        it('should save the template', function(done)
          request(url)
            .post('/api/form/template')
            .query(email: credentials.email, token: credentials.token)
            .send(
              _admin_id: credentials.admin._id,
              template: templateForm,
            )
            .end(function(err, res)
              templateFormId = res.body._id;
              res.body.should.have.property('_admin_id').and.be.equal(''+credentials.admin._id);
              res.body.should.have.property('template').and.be.instanceof(Object);
              done();
            );
        );
      );

      describe('GET /api/form/template/:id', function()
        it('Should respond with template data', function(done)
          request(url)
            .get('/api/form/template/' + templateFormId)
            .query(email: credentials.email, token: credentials.token)
            .end(function(err, res)
              ...
              done();
            );
        );
      );

      describe('GET /api/form/template/company/:id', function()
        it('Should respond with company template data', function(done)
          request(url)
            .get('/api/form/template/company/' + credentials.admin._id)
            .query(email: credentials.email, token: credentials.token)
            .end(function(err, res)
              ...
              done();
            );
        );
      );

      describe('DELETE /api/form/template/:template_id', function()
        it('Should delete the template data', function(done)
          request(url)
            .delete('/api/form/template/' + templateFormId)
            .query(email: credentials.email, token: credentials.token)
            .end(function(err, res)
              ...
              done();
            );
        );
      );
    );


    describe("Submitted Forms", function() 
      describe('POST /api/form/patient', function()
        it('should save submitted form', function(done)
          request(url)
            .post('/api/form/patient')
            .query(email: credentials.email, token: credentials.token)
            .send(
              _admin_id: credentials.admin._id,
              form: submittedForm,
              firstName: "Jimbo",
              lastName: "Cruise",
              patientEmail: "jcruise@tomcruise.com",
            )
            .end(function(err, res)
              ...
              submittedFormId = res.body._id;
              done();
            );
        );
      );

      describe('GET /api/form/:form_id', function()
        it('should respond with submitted form data', function(done)
          request(url)
            .get('/api/form/patient/' + submittedFormId)
            .query(email: credentials.email, token: credentials.token)
            .end(function(err, res)
              res.body.should.have.property('_id');

              ...

              done();
            );
        );
      );
    );


    after(function() 
      exit();
    );
);

无论我给测试套件什么超时,它都会给出“错误:超过 5000 毫秒的超时”。除了“它应该运行测试套件”之外,所有测试都通过了。我还要注意,我还有其他不使用包装器的测试文件。首先调用上面的这个测试套件,创建管理员用户,测试套件超时,然后清除管理文档,然后继续进行其他测试。最后,它打印出围绕 ConfigureAdmin 函数包装的测试。

【问题讨论】:

【参考方案1】:

在你的包装器中,你有这个:

// Call the actual test suite, pass it the auth credentials.
describe("Test Suite", function() 
    it("should run the test suite", function(done) 
        // No matter what the timeout is set to it still exceeds it
        this.timeout(5000);
        test_suite(
            email: email,
            password: password,
            token: token,
            admin: admin
        , done);
    );
);

test_suite 函数包含更多对describeit 的调用。 如果您这样做,Mocha 不会引发任何错误,但它不会按您预期的方式工作。 Mocha 执行如下测试:

    Mocha 发现测试。 describe 调用 Mocha 注册新套房。他们的回调立即执行。 it 调用使用 Mocha 注册新测试。它们的回调在Mocha 运行测试时执行。钩子调用(beforeafter 等)也在向 Mocha 注册钩子,以便稍后执行,在 Mocha 运行测试时

    Mocha 运行已注册的测试。

当你把describe 放在it 里面时,会出现一个问题:这个describe 被执行并且Mocha 注册一个新套件,但是到时候它已注册,执行流程您所有的describe 回调之外。因此,这个新套件在匿名***套件(Mocha 自动创建)上注册,并从该***套件继承其超时值。看看这个例子:

describe("top", function () 
    it("test", function () 
        this.timeout(5000);
        describe("inner", function () 
            it("inner test", function (done) 
                setTimeout(function () 
                    done();
                , 6000);
            );
        );
    );

    describe("inner 2", function () 
        it("inner test 2", function () );
    );

);

describe("top 2", function ()
    it("test 3", function () );
);

如果你运行它,你会得到:

  top
    ✓ test 
    inner 2
      ✓ inner test 2 

  top 2
    ✓ test 3 

  inner
    1) inner test


  3 passing (2s)
  1 failing

  1) inner inner test:
     Error: timeout of 2000ms exceeded
     [... etc ...]

请注意 inner 套件,即使它出现在 javascript 代码中的 top 内部,但在 Mocha 的报告中显示在它的外部。 (另一方面,inner 2 恰好出现在它应该出现的位置。)这就是我上面解释的内容:当 Mocha 注册这个套件时,执行流程在 toptop 2 describe 之外来电。还要注意timeout 调用是如何无用的。

如果您运行上述相同的代码但使用mocha --timeout 7000,则测试将通过,因为默认超时值(包括 Mocha 创建的匿名套件)现在是 7000。

此外,您的套件目前需要在测试之间有一定的顺序。摩卡不是为此而设计的。为您的测试设置夹具应该在beforebeforeEach 钩子中完成,而拆除它们应该在afterafterEach 中完成。因此,这不仅仅是将describe 排除在it 调用之外的问题。

【讨论】:

以上是关于无论如何都超过了摩卡超时的主要内容,如果未能解决你的问题,请参考以下文章

返回承诺时摩卡超过2000毫秒超时[重复]

摩卡柴解决多个承诺

弹性beantalk部署时间超过超时时间,我如何增加超时时间

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

Angular如何知道请求是否超时超过三次?

如何在heroku中有超过30秒的响应超时