web-dev-qa-db-ja.com

各Mochaテストの前にExpressアプリが実行されていることを確認する

ExpressJS、NodeJS、Mongoose、Mochaを使用してREST APIの開発に取り組んでいます。

ExpressJSのセットアップとMongooseへの接続を担当するapp.coffeeファイルがあります。私がこれを設定した方法は、Mongooseが最初に接続され、それが通過すると、ExpressJSアプリが起動するというものです。

問題は、Mochaをセットアップするときに、テストケースを実行する前に、app.coffeeに存在するExpressJSアプリがすべての非同期コードを含めて完全に正常に開始されていることを確認する必要があることです。

そのために、test_helper.coffeeを作成し、その中に次のコードを配置しましたが、app.coffeeのコードが完全に実行を完了していなくても、テストケースは実行を開始します。これは実際には理にかなっています。

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

一言で言えば、テストケースを実行する前に、ExpressJSアプリがセットアップを完全に完了していることを確認したいと思います。

どうすればそれができますか?

19
Haseeb Khan

パーティーに遅れましたが、エクスプレスアプリ用にmochaテストスイートを設定する最良の方法は、次のように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と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 testで開始し、アプリをnpm startで開始できます。

それが役に立てば幸い! ps:この驚くべき例を見て学んだことのほとんど: https://github.com/madhums/node-express-mongoose-demo

14
tmaximini

エクスプレスアプリのテストに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);
     });
});
_

同じ考えがモカにも当てはまるはずです。 これはモカについて説明している記事ですbeforeAllbeforeに変更するだけです。

3
jjbskir

もっと簡単な方法があるかもしれませんが、私は機能テストを自動化するために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」をgitpre-commitフックとして追加します。このように、すべてのテストに合格せずにコミットすることはできません

1
Raf

app.listen メソッドは、すべての準備ができたときに実行されるコールバックを受け取ります。したがって、完了したコールバックをそこで渡すことができる必要があります。何かのようなもの

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

基本的にあなたがする必要がある2つのことが必要です。

  1. サーバーがリッスンする前に、データベースが接続されていることを確認してください
  2. テストを実行する前に、アプリが起動していることを確認してください。

フレームワークには、イベントを使用してこれを処理する方法がすでにあります。

これをデータベース接続に追加します。これにより、接続が終了したときに「ready」を発行するようにmongooseに指示します。

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

次に、エクスプレスに「準備完了」を待ってから聞くように指示します。完了すると、「appStarted」が発行されます。

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

サーバーがスムーズに起動することを確認するために、これはすべてモカの良い習慣です。以前にMocha統合を完了するには(私はPromisesを使用するのが好きです):

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

アプリをテストするためにポートをリッスンする必要はありません。 supertest テストライブラリをアプリで使用できます。問題はありません。

ただし、おそらくデータベースまたはRedisクライアントに接続する必要があります。これは、アプリのconfigureメソッドで実行できます。ノードはモジュールをキャッシュするため、再接続せずに異なるテストモジュールでアプリモジュールを要求できます。

0
Behlül Uçar