Как экспортировать приложение для экспресс-узлов для chai-http - PullRequest
7 голосов
/ 15 марта 2019

У меня есть экспресс-приложение с несколькими конечными точками, и в настоящее время я тестирую его, используя mocha, chai и chai-http.Это работало нормально, пока я не добавил логику для соединения с пулом Монго и не начал создавать конечные точки, которые зависели от соединения с БД.По сути, прежде чем импортировать свои маршруты API и запустить приложение, я хочу убедиться, что я подключен к Монго.

Моя проблема в том, что у меня возникают проблемы с пониманием того, как я могу экспортировать свое приложение для chai-http, но также проверяю, есть ли соединение с БД перед тестированием любых конечных точек.

Здесь ясоединяясь с Монго, затем с помощью обратного вызова применяю мой API и запускаю приложение.Проблема этого примера в том, что мои тесты начнутся до того, как будет установлено соединение с базой данных, и до того, как будут определены какие-либо конечные точки.Я мог бы переместить app.listen и api(app) за пределы обратного вызова MongoPool.connect(), но у меня все еще остается проблема отсутствия соединения с БД во время выполнения тестов, поэтому мои конечные точки не пройдут.

server.js

import express from 'express';
import api from './api';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 3000;
MongoPool.connect((err, success) => {
    if (err) throw err;
    if (success) {
        console.log("Connected to db.")
        // apply express router endpoints to app
        api(app);
        app.listen(port, () => {
            console.log(`App listening on port ${port}`);
        })
    } else {
        throw "Couldnt connect to db";
    }

})
export default app;

Как я могу проверить свои конечные точки, используя chai-http, при этом убедившись, что перед пуском тестов есть пул соединения?Мне кажется грязным писать мое приложение так, чтобы оно соответствовало тестам, которые я использую.Это проблема проектирования с моей реализацией пула?Есть ли лучший способ проверить мои конечные точки с помощью chai-http?

Вот тест, который я запускаю

test.js

let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../server').default;;
let should = chai.should();


chai.use(chaiHttp);
//Our parent block
describe('Forecast', () => {
/*
  * Test the /GET route
  */
  describe('/GET forecast', () => {
      it('it should GET the forecast', (done) => {
        chai.request(server)
            .get('/api/forecast?type=grid&lat=39.2667&long=-81.5615')
            .end((err, res) => {
                res.should.have.status(200);
              done();
            });
      });
  });

});

И это конечная точка, которую я тестирую

/ api / forecast.js

import express from 'express';
import MongoPool from '../lib/MongoPool';
let router = express.Router();
let db = MongoPool.db();

router.get('/forecast', (req, res) => {
    // do something with DB here
})

export default router;

Спасибо за любую помощь

Ответы [ 6 ]

2 голосов
/ 20 марта 2019

Express app является экземпляром EventEmitter, поэтому мы можем легко подписаться на события. то есть app может прослушивать событие «готово».

Ваш server.js файл будет выглядеть ниже,

import express from 'express';
import api from './api';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 3000;

app.on('ready', function() {
  app.listen(3000, function() {
    console.log('app is ready');
  });
});

MongoPool.connect((err, success) => {
  if (err) throw err;
  if (success) {
    console.log('Connected to db.');
    // apply express router endpoints to app
    api(app);

    // All OK - fire (emit) a ready event.
    app.emit('ready');
  } else {
    throw 'Couldnt connect to db';
  }
});

export default app;
1 голос
/ 24 марта 2019

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

В server.js Я подключаюсь к пулу монго, а затем отправляю событие 'ready' на экспресс app. Затем в тесте я могу использовать before(), чтобы дождаться появления события «готово» в приложении. Как только это произойдет, я могу приступить к выполнению теста.

server.js

import express from 'express';
import bodyParser from 'body-parser';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 5000;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

(async () => {
    await MongoPool.connect();
    console.log("Connected to db.");
    require('./api').default(app);
    app.listen(port, () => {
        console.log(`Listening on port ${port}.`)
        app.emit("ready");
    });
})();

export default app;

test.js

//Require the dev-dependencies
import chai from 'chai';
import chaiHttp from 'chai-http';
import server from '../src/server'; 
let should = chai.should();
chai.use(chaiHttp);

before(done => {
  server.on("ready", () => {
    done();
  })
})
describe('Forecast', () => {
  describe('/GET forecast', () => {
    it('it should GET the forecast', (done) => {
      chai.request(server)
          .get('/api/forecast?type=grid&lat=39.2667&long=-81.5615')
          .end((err, res) => {
              res.should.have.status(200);
            done();
          });
    });
  });

});
1 голос
/ 24 марта 2019

Вы можете использовать running server вместо express instance.

Запустите ваш сервер с private port, затем пройдите тестирование на работающем сервере.

напр .: PORT=9876 node server.js

В вашем тестовом блоке используйте chai.request('http://localhost:9876') (замените протоколом, ip сервера ...) вместо chai.request(server).

1 голос
/ 19 марта 2019

Используйте Перед функцией в своих тестах, как показано ниже:

 describe('Forecast', () => {
  before(function(done){
   checkMongoPool(done); // this function should wait and ensure mongo connection is established.
  });
  it('/GET forecast', function(cb){
  // write test code here ...
  });
});

И вы можете проверить соединение с mongodb следующим образом:

Метод 1: просто проверьте свойство readyState -

mongoose.connection.readyState == 0; // not connected
mongoose.connection.readyState == 1; // connected`

Метод 2: использовать события

mongoose.connection.on('connected', function(){});
mongoose.connection.on('error', function(){});
mongoose.connection.on('disconnected', function(){});
1 голос
/ 19 марта 2019

Просто создайте нижеприведенную функцию для подключения к Монго и сделайте так, чтобы она возвращала обещание. затем используйте await, чтобы дождаться соединения и возврата. функция может быть такой

function dbconnect(){
    return new Promise(function(resolve, reject){

    MongoPool.connect((err, success) => {
    if (err) reject(err);
    if (success) {
        resolve({'status' : true})
    } else {
        reject(new Error({'status' : false}))
    }

})
    })
}

А затем используйте

await dbconnect();
api(app);
app.listen(port, () => {
    console.log(`App listening on port ${port}`);
})

Теперь строка ожидания будет ожидать подключения функции к БД, а затем вернет успех или ошибку в случае сбоя. Это своего рода решение, которое вы можете использовать, но я бы не советовал вам делать то, что мы на самом деле делаем.

создавать сервисы и использовать их в маршрутах, не писать код БД напрямую в маршрутах.

и

при написании тестов для маршрутов макетировать / заглушать эти сервисы и тестировать сервисы отдельно в других тестовых случаях, когда вы просто передаете объект БД, а сервис добавит функции к этим объектам БД, поэтому в тестах вы можете подключиться к БД и передать их возражать против этих сервисов для тестирования функций, это даст вам дополнительное преимущество, если вы хотите использовать фиктивную / тестовую БД для тестирования, вы можете установить это в тестовых примерах.

0 голосов
/ 24 марта 2019

Если вы используете собственный mongodb клиент, вы можете реализовать пул многократного использования, например:

MongoPool.js
// This creates a pool with default size of 5
// This gives client; You can add few lines to get db if you wish
// connection is a promise
let connection;
module.exports.getConnection = () => {
  connection = MongoClient(url).connect()
}

module.exports.getClient = () => connection

Now in your test you could,
const { getConnection } = require('./MongoPool')
...
describe('Forecast', () => {
  // get client connection
  getConnection()
  ...

In your route:
...
const { getClient } = require('./MongoPool')
router.get('/forecast', (req, res) => {
    // if you made sure you called getConnection() elsewhere in your code, client is a promise (which resolves to mongodb connection pool)
    const client = getClient()
    // do something with DB here
    // then you could do something like client.db('db-name').then(//more).catch()
})
...