2013-09-22 34 views
15

我正在使用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应用程序在执行任何测试用例之前已完全完成其设置。

我该怎么做?

+0

我遇到了完全类似的问题。我重新设计了我的快速服务器,现在不要等待数据库连接或任何类型的异步初始化。这对于REST服务器来说也很理想,因为即使没有请求进入REST环境,也不需要连接到数据库。此外,每次通话并不一定需要所有型号。 在我的情况下,我几乎每次调用都需要初始化数据库。 – Kamrul

+0

@Kamrul:你可以请你分享一些示例代码,如何做到这一点? –

回答

1

你不需要听一个端口来测试你的应用程序。您可以使用supertest测试库与您的应用程序,它应该没问题。

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

+0

问题是我的应用程序安装程序是异步的,包括当我的快速路线准备好时,所以超级跑车每次尝试击中该路线都会失败,因为它启动得太快。 – writofmandamus

+0

你确实需要听一个端口。你可以让supertest [为你做](https://github.com/visionmedia/supertest/blob/199​​506d8dbfe0bb1434fc07c38cdcd1ab4c7c926/lib/test.js#L59)。 – dvlsg

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 hook。这种方式,你不能没有通过所有的测试

15

我迟到了派对,但我发现设置我的摩卡测试套件的快速应用程序的最佳方式是使我的app.js或server.js文件导出应用程序对象,像这样:

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和摩卡):

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

现在你可以开始你的测试套件npm test和您的应用程序npm start

希望它有帮助! PS:大部分的东西我从看着这个惊人的例子了解到: https://github.com/madhums/node-express-mongoose-demo

+5

supertest是否知道expressjs应用程序何时可以使用?当你的http动词初始化时,你如何保证数据库准备好使用? – raffomania

+0

,因为我从我的app.js文件中导出应用程序并要求它位于每个测试文件的顶部 – tmaximini

+3

但是db怎么办? AFAIK你必须使用'mongoose.connection.once('open',callback)''然后添加你的路由。这意味着应用程序是异步初始化的。你如何处理? – raffomania

2

我碰到了同样的问题,而使用茉莉/ 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

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

+0

的出口应用程序谢谢,这是迄今为止对我来说最好的解决方案 – DanP

+0

是的这也适用于我,只需添加发射后,你启动/启动服务器,然后检查app.on它在前功能 - 最好的答案 – AKMorris

0

app.listen方法需要一个回调,当一切准备就绪时运行。所以,你需要能够将完成的回调传递给那里。类似于

before (done) -> 
    var app = require(__dirname + '/../src/app') 
    app.listen(3000, done)