【问题标题】:How to export node express app for chai-http如何为 chai-http 导出 node express 应用程序
【发布时间】:2019-08-06 03:20:20
【问题描述】:

我有一个带有几个端点的 express 应用程序,目前正在使用 mocha、chai 和 chai-http 对其进行测试。在我为池化 mongo 连接添加逻辑并开始构建依赖于数据库连接的端点之前,这一切正常。基本上,在我导入我的 API 路由并启动应用程序之前,我想确保我已连接到 mongo。

我的问题是我无法理解如何为 chai-http 导出我的应用程序,但还要确保在测试任何端点之前存在数据库连接。

在这里,我连接到 mongo,然后在回调中应用我的 API 并启动应用程序。这个例子的问题是我的测试将在连接到数据库之前开始,并且在定义任何端点之前。我可以将app.listenapi(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;

感谢您的帮助

【问题讨论】:

  • 嗨,艾萨克。从您的测试中,您可以初始化您的应用程序并等待应用程序连接,因此,在 server.js 中,您可以定义一个“初始化”方法返回一个承诺/回调/异步函数并在您开始测试时调用此方法(您也可以可以在初始化方法中放置逻辑来查看服务器是否正在运行以开始监听连接、连接到 mongodb 等)问候

标签: javascript node.js mongodb express chai


【解决方案1】:

在收到一些好的反馈后,我发现这个解决方案最适合我,基于 Gomzy's answerVikash Singh's answer

server.js 中,我连接到 mongo 池,然后在 express 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();
          });
    });
  });

});

【讨论】:

  • 似乎是最好的解决方案。感谢分享。
  • 有人用这种方法得到TypeError: server.on is not a function吗?
  • @SimonBarker 在你的情况下,server 是 express 的一个实例吗?
【解决方案2】:

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;

【讨论】:

  • 谢谢,发送和监听事件在很大程度上解决了我的问题。
【解决方案3】:

只需在下面创建一个函数来连接到 mongo 并使其返回一个 Promise。 然后使用 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}`);
})

现在等待行将等待函数连接到数据库,然后在失败的情况下返回成功或错误。 这是您可以使用的一种解决方案,但我不建议您这样做,我们实际上是这样做的。

创建服务并在路由中使用这些服务,不要直接在路由中编写数据库代码。

在为路由模拟/存根这些服务编写测试时,并在其他测试用例中单独测试服务,您只需传递数据库对象,服务将在该数据库对象上添加函数,因此在测试中您可以连接到数据库并传递它反对这些服务来测试功能,它会给你额外的好处,如果你想使用虚拟/测试数据库进行测试,你可以在测试用例中设置它。

【讨论】:

    【解决方案4】:

    在您的测试中使用 Before 函数,如下所示:

     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 连接:

    方法一:只检查readyState属性-

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

    方法二:使用事件

    mongoose.connection.on('connected', function(){});
    mongoose.connection.on('error', function(){});
    mongoose.connection.on('disconnected', function(){});
    

    【讨论】:

    • 虽然我没有使用猫鼬,但谢谢你,因为我不知道before() 甚至是一个东西哈哈,但它对我的解决方案有很大帮助。
    【解决方案5】:

    您可以使用running server 代替express instance

    使用private port 启动您的服务器,然后在正在运行的服务器上进行测试。

    例如:PORT=9876 node server.js

    在您的测试块中,使用 chai.request('http://localhost:9876')(替换为您的协议、服务器 ip...)而不是 chai.request(server)

    【讨论】:

    • 感谢您的回答,我应该更好地查看文档,因为我认为我只能将服务器对象传递给 chai.request
    【解决方案6】:

    如果您使用本机 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()
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 2020-10-17
      • 2020-07-02
      相关资源
      最近更新 更多