Обеспечение экспресс-приложения выполняется перед каждым тестом Mocha

Я работаю над разработкой REST API с помощью ExpressJS, NodeJS, Mongoose и Mocha.

Дело в том, что у меня есть файл app.coffee, который отвечает за настройку ExpressJS и подключение к Mongoose. Способ, которым я настроил это, заключается в том, что Mongoose подключен первым, и если это пройдет, то приложение ExpressJS будет запущено.

Проблема заключается в том, что при настройке Mocha мне нужно убедиться, что приложение ExpressJS, существующее в app.coffee, полностью запущено, включая весь асинхронный код, прежде чем какой-либо тестовый файл будет выполнен.

Для этого я создал test_helper.coffee и поместил в него следующий код, но тестовые окна начинают свое выполнение, даже если код в app.coffee не завершил свое выполнение полностью, что на самом деле имеет смысл:

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

Вкратце, я хочу убедиться, что приложение ExpressJS полностью завершило настройку до того, как будет выполнен любой тестовый файл.

Как я могу это сделать?

Ответы

Ответ 1

Я опаздываю на вечеринку, но я нашел лучший способ настроить мой тестовый пакет для мокко для экспресс-приложения, чтобы сделать файл 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 (убедитесь, что у вас есть nodemon и mocha в devDependencies):

"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

Ответ 2

Вам не нужно прослушивать порт для тестирования вашего приложения. Вы можете использовать supertest тестовую библиотеку с вашим приложением, и это должно быть нормально.

Вероятно, вам нужно будет подключиться к базе данных или клиенту redis. Вы можете сделать это в методе configure вашего приложения. Поскольку node кэширует модули, вы можете потребовать модуль приложения в разных тестовых модулях без повторного подключения.

Ответ 3

Там может быть более простой способ, но я пошел в Grunt для автоматизации моих функциональных тестов. Там есть плагин express и mocha для достижения вашей цели. Мой файл grunt:

'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'])
}

bonus: добавьте "grunt" как крюк git pre-commit. Таким образом, вы не можете совершать, не передавая все тесты

Ответ 4

Я столкнулся с той же проблемой при использовании 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);
     });
});

Такая же идея должна работать и на мокко. Вот статья, объясняющая это для мокко. Вы должны просто изменить beforeAll на before.

Ответ 5

Метод app.listen принимает обратный вызов, который запускается, когда все готово. Таким образом, вы должны иметь возможность пройти туда обратный вызов. Что-то вроде

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