确保Express App在每次Mocha测试之前运行

时间:2013-09-22 08:14:49

标签: node.js express mongoose mocha superagent

我正在使用ExpressJS,NodeJS,Mongoose和Mocha开发REST API。

问题是我有一个app.coffee文件,它负责设置ExpressJS并连接到Mongoose。我设置它的方式是首先连接Mongoose,如果通过,则启动ExpressJS应用程序。

问题在于,在设置Mocha时,我需要确保app.coffee中存在的ExpressJS App在执行任何测试用例之前已经完全成功启动,包括所有异步代码。

为此,我创建了一个test_helper.coffee,并在其中放置了以下代码,但是,即使app.coffee中的代码没有完全执行完全实际有意义,测试用例也会开始执行:

before (done) ->
  require(__dirname + '/../src/app')
  done()

简而言之,我想确保ExpressJS应用程序在执行任何测试用例之前已完全完成其设置。

我怎么能这样做?

6 个答案:

答案 0 :(得分:14)

我迟到了,但我发现为Express应用程序设置我的mocha测试套件的最佳方法是让我的app.js或server.js文件导出app对象,如下所示:

var mongoose = require('mongoose');
var express = require('express');
require('express-mongoose');

var env = process.env.NODE_ENV || 'development';
var config = require('./config/config')[env];

var models = require('./app/models');
var middleware = require('./app/middleware');
var routes = require('./app/routes');

var app = express();

app.set('port', process.env.PORT || config.port || 3000);
app.set('views', __dirname + '/app/views');
app.set('view engine', 'jade');

// database
mongoose.connect(config.db);

// middleware
middleware(app);

// Application routes
routes(app);

app.listen(app.get('port'));
console.log('Express server listening on port ' + app.get('port'));

// export app so we can test it
exports = module.exports = app;

确保您的配置文件具有不同的环境,如开发,测试,生产设置:

var path = require('path');
var rootPath = path.normalize(__dirname + '/..');

module.exports = {
  development: {
    db: 'mongodb://localhost/my_dev_db',
    port: 3000
  },
  test: {
    db: 'mongodb://localhost/my_test_db',
    port: 8888
  },
  production: {
    // ...
  }
}

然后在您的测试文件中,您可以继续使用您的应用程序,它将连接到正确的数据库和正确的端口:

var should = require('chai').should();
var request = require('supertest');
var mongoose = require('mongoose');

var app = require('../app');
var agent = request.agent(app);

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

    // get users
    describe('GET /api/users', function() {
      it('returns users as JSON', function(done) {
        agent
        .get('/api/users')
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) return done(err);
          res.body.should.have.property('users').and.be.instanceof(Array);
          done();
        });
      });
    });

最后,要启动整个怪物,请在package.json中包含此内容(确保在devDependencies中包含nodemon和mocha):

"scripts": {
    "start": "NODE_ENV=development ./node_modules/.bin/nodemon app.js",
    "test": "NODE_ENV=test ./node_modules/.bin/mocha --reporter spec test/**.js"
  }

现在,您可以使用npm testnpm start的应用启动测试套件。

希望它有所帮助! ps:我从查看这个惊人的例子中学到的大部分内容: https://github.com/madhums/node-express-mongoose-demo

答案 1 :(得分:3)

我在使用jasmine / supertest来测试我的快递应用时遇到了同样的问题。我通过在应用程序准备好时发出并且之后只运行我的测试来解决问题。这是我的目录结构

- server.js
- spec
    - setup.spec.js
    - test.spec.js

server.js中,当您的服务器设置好并准备好运行测试时,请添加app.emit('started');。并确保导出您的应用程序!在setup.spec.js中,您可以观察要发出的事件。

<强> server.js

const express = require('express');
const app = express();
module.exports = app; // for testing

setTimeout(() => {
    app.listen(process.env.PORT || 3000);
});

<强> setup.spec.js

const server = require('../index');

beforeAll(done => server.on('started', done));

<强> test.spec.js

const request = require('supertest');
const server = require('../index');

describe('test', () => {
    it('test server works', done => {
        request(server).get('/test').expect(200);
     });
});

同样的想法也适用于摩卡。 Here is an article explaining this for mocha。您只需将beforeAll更改为before

答案 2 :(得分:1)

您无需收听用于测试应用的端口。您可以在应用中使用supertest测试库,它应该没问题。

您可能需要连接到数据库或redis客户端。您可以在应用的configure方法中执行此操作。由于节点缓存模块,您可以在不重新连接的情况下在不同的测试模块中使用app模块。

答案 3 :(得分:1)

可能有一种更简单的方法,但我去了Grunt来自动化我的功能测试。有一个快速和摩卡插件来达到你的目标。我的gruntfile:

'use strict';

module.exports = function (grunt) {
grunt.initConfig({
    express: {
        options: {}
      , test: {
            options: {
                script: './app.js'
            }
        }
    }
  , simplemocha: {
        options: {
            globals: ['should']
          , timeout: 8000
          , ignoreLeaks: false
          , ui: 'bdd'
          , reporter: 'tap'
        }
      , all: { src: ['tests/*.test.js'] }
    }
})

grunt.loadNpmTasks('grunt-express-server')
grunt.loadNpmTasks('grunt-simple-mocha')

grunt.registerTask('default', ['express:test', 'simplemocha', 'express:test:stop'])
}

奖励:添加'grunt'作为git pre-commit钩子。这样,如果不通过所有测试,就无法提交

答案 4 :(得分:0)

app.listen方法接受一切准备就绪时运行的回调。所以,你需要能够在那里传递完成的回调。像

这样的东西
before (done) ->
  var app = require(__dirname + '/../src/app')
  app.listen(3000, done)

答案 5 :(得分:0)

基本上,您需要做两件事。

  1. 在服务器侦听之前确保数据库已连接
  2. 在运行测试之前,请确保该应用已启动。

该框架已经有一种通过使用事件来处理此问题的方法。

将此添加到您的数据库连接中,指示猫鼬在完成连接后发出“就绪”消息。

mongoose.connection.once('open', function() { 
   // All OK - fire (emit) a ready event. 
   console.log('Connected to MongoDB');
   app.emit('ready'); 
});

然后指示Express在收听之前等待“就绪”。完成后,它发出:'appStarted'。

app.on('ready', function() { 
    app.listen(PORT, function(){ 
        console.log("Server listing on port:",PORT); 
        app.emit("appStarted");
    }); 
}); 

除了Mocha以外,这都是所有好的做法,以确保您的服务器平稳启动。要完成您之前的Mocha集成(我喜欢使用Promises):

before(function() {        
    return new Promise((resolve,reject) => {
        app.on("appStarted", function(){
            return resolve();
        }); 
    });
});