Mocha 测试执行时间过长

Posted

技术标签:

【中文标题】Mocha 测试执行时间过长【英文标题】:Mocha tests taking too long to execute 【发布时间】:2015-05-07 14:01:29 【问题描述】:

所以我正在开发一个 express.js 应用程序,其中我有一个猫鼬模型用户。我编写了一个测试文件(使用 Mocha)来测试 save() 函数,但是我所有的测试都需要很长时间才能执行并最终超时。

这是我得到的错误:

  Testing - Server - User - Model
    Testing save()
      1) should be able to save without problems
      2) should fail to save an exisitng user again
      3) should should an error when try to save with empty email
      4) should give an error when try to save with empty password
    5) "after all" hook


  0 passing (8s)
  5 failing

  1) Testing - Server - User - Model Testing save() should be able to save without problems:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  2) Testing - Server - User - Model Testing save() should fail to save an exisitng user again:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  3) Testing - Server - User - Model Testing save() should should an error when try to save with empty email:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  4) Testing - Server - User - Model Testing save() should give an error when try to save with empty password:
     Uncaught AssertionError: expected null to exist
      at Promise.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/test/models/user.server.model.test.js:69:12)
      at Promise.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
      at Promise.emit (events.js:98:17)
      at Promise.emit (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
      at Promise.fulfill (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
      at handleSave (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/model.js:133:13)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/utils.js:408:16
      at model.save (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/model.js:222:7)
      at model._done (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:59:24)
      at _next (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:52:28)
      at fnWrapper (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:159:8)
      at model.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/models/user.js:22:46)
      at _next (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:50:30)
      at fnWrapper (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:159:8)
      at complete (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:992:5)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:983:20
      at ObjectId.SchemaType.doValidate (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/schematype.js:603:22)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:974:9
      at process._tickCallback (node.js:442:13)

  5) Testing - Server - User - Model "after all" hook:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

这是我的测试文件:

// Module dependencies
var should = require("should");
var mongoose = require("mongoose");
var config = require('../../config/config');
var nodemailer = require('nodemailer');
var bcrypt = require('bcryptjs');

// Get User model
var User = require('../../models/user')(mongoose, config, bcrypt, nodemailer).User;

// Define global test variables
var user;
var user2;

// Unit tests
describe('Testing - Server - User - Model', function()

    // Since its before - it happens once ONCE before ALL the tests
    before(function(done)
        // Since we're using the global variables don't use var in front of them
        user = new User(
            email: 'a@a.com',
            password: 'a'
        );

        // Another user with same details as the first user cos
        // For a test case, where we try to insert 2 records with same details (should fail as exprected)
        user2 = new User(
            email: 'a@a.com',
            password: 'a'
        );
        done();
    );

    // Testing function #1 - save()
    describe('Testing save()', function()

        // Test case #1 - save normally
        it('should be able to save without problems', function(done)
            try  
                user.save(done);
             catch (x)  
                done(x);
            
        );

        // Test case #2 - should fail to save an exisitng user again
        it('should fail to save an exisitng user again', function(done)
            user.save(function()
                user2.save(function(err)
                    should.exist(err);
                    done();
                );
            );
        )

        // Test case #3 - should give an error when try to save with empty email
        it('should should an error when try to save with empty email', function(done)
            user.email = '';
            return user.save(function(err)
                should.exist(err);
                done();
            );
        );

        // Test case #4 - should give an error when try to save with empty password
        it('should give an error when try to save with empty password', function(done)
            return user.save(function(err)
                should.exist(err);
                done();
            );
        );
    );

    after(function(done)
        User.remove().exec(done);
    );
);

这是我的用户模型文件:

module.exports = function(mongoose, config, bcrypt, nodemailer)

  // User schema 
  var userSchema = new mongoose.Schema(
    email: 
      type: String,
      unique: true,
      lowercase: true
    ,
    password: 
      type: String,
      select: false
    
  );

  // Makes sure that our passwords are always hashed before saving to the database
  // Refer to sessionBuddy's resources for more info on this 
  userSchema.pre('save', function(next) 
    var user = this;

    // Only hash the password if its modified or new
    if (!user.isModified('password')) return next();

    // Generate salt
    bcrypt.genSalt(config.SALT_WORK_FACTOR, function(err, salt) 
      if (err) return next(err);

      // hash the password along with the salt
      bcrypt.hash(user.password, salt, function(err, hash) 
        if (err) return next(err);

        // overwrite the cleartext password with the hashed one
        user.password = hash;
        next();
      );
    );
  );

  // Password verification for cleartext and hashed passwords
  userSchema.methods.comparePassword = function(password, done) 
    bcrypt.compare(password, this.password, function(err, isMatch) 
      done(err, isMatch);
    );
  ;

  var User = mongoose.model('User', userSchema);

  return
    User : User
  

我还尝试了 try/catch 方法来获取该线程的承诺:In mocha testing while calling asynchronous function how to avoid the timeout Error: timeout of 2000ms exceeded. 但这也不起作用。

感谢任何帮助! 谢谢

编辑:正如 cmets 中所建议的,我没有连接到测试文件中的数据库。 EDIT2:现在在最后 2 个测试中出现以下错误 - “未捕获的 AssertionError:预期 null 存在” EDIT3:实际上我的架构可以将“电子邮件”和“密码”保存为空,因为我没有将必填字段设置为真,在更新我的架构后,它可以工作。

【问题讨论】:

看起来您实际上并没有连接到 mongodb 数据库。如果你不这样做,你的所有请求都将被排队并且永远不会被执行。 另外,如果您想在没有设置数据库的情况下仍然拥有测试环境,您可以使用 rewire 重新定义 User#save 是的,很抱歉我实际上并没有连接到数据库。谢谢大家的帮助 我现在实际上遇到了另一个问题。对于最后 2 次测试,我收到以下消息:“Uncaught AssertionError: expected null to exist”知道这意味着什么吗? 【参考方案1】:

正如 cmets 中所指出的,您实际上并没有连接到 mongodb 数据库。您的所有请求都将由 Mongoose 排队,并且在您连接到数据库之前永远不会执行(从而在您的测试中产生超时)。

编辑 至于你的第二个问题,当它实际上没有产生任何错误时,你期望错误存在。此行未通过您的测试:

should.exist(err);

您应该检查您的模型。在您的第三个测试用例中,您要求用户拥有电子邮件,但您的模型并没有强制要求。密码也是一样。 此外,您不会在测试中将密码设为空。

【讨论】:

是的,你是对的。我刚刚对它进行了编辑。感谢您的帮助

以上是关于Mocha 测试执行时间过长的主要内容,如果未能解决你的问题,请参考以下文章

在 mocha 中,如何在执行另一个测试之前等待异步测试结束?

如何在多个文件中设置mocha测试用例的执行顺序

使用 mocha 进行测试时的 Node.js CronJob 执行

Mocha beforeEach vs 执行前

Mocha:隐藏成功测试的 console.log 输出

Mocha describe 生命周期