【问题标题】:How to correctly close express server between tests using mocha and chai如何在使用 mocha 和 chai 的测试之间正确关闭 express 服务器
【发布时间】:2018-04-12 06:54:10
【问题描述】:

我正在寻找一种正确的方法来在测试之间完全重置我的快速服务器!看来这不仅仅是我的问题,很多其他用户也问过同样的问题, 许多博客文章都在讨论这个论点。建议的解决方案对我来说既不奏效也不令人满意。这里有另一个类似的问题和一篇文章很好地描述了这个问题并提出了一些解决方案:

堆栈溢出 Closing an express server after running jasmine specs

博客: https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/

这里专门创建了一个包来解决这个问题: https://www.npmjs.com/package/server-destroy

现在,一个最小的工作示例来重现我的情况。 在被测代码中,创建了一个快递服务器;当在某个端点上调用时,服务器会增加一个值并返回它:

( function() {
   'use strict'

   const enableDestroy = require( 'server-destroy' )
   const app = require( 'express' )()
   const http = require( 'http' )

   let val = 0

   app.use( '/inc', (req, res) => {
      val ++
      res.send(val.toString())
   } )

   const server = http.createServer( app )

   server.listen( 3000 )

   enableDestroy(server);

   module.exports = server

} )()

测试包含两个相同的测试用例;他们都在端点上调用服务器,并检查返回的值。 提供before_eachafter_each 部分是为了确保在运行单个测试用例之前创建新连接,然后关闭,以确保两个测试用例之间的独立性:

const chai = require( 'chai' )
const chaiHttp = require( 'chai-http' )
const expect = chai.expect
chai.use( chaiHttp )

let server

describe( 'first test group', () => {
   beforeEach( () => {
      server = require( './server' )
   } ),

   afterEach( ( done ) => {
      server.destroy( done )
      delete require.cache[require.resolve( './server' )]
   } ),

   it( 'should respond 1', ( done ) => {
      chai.request( server )
         .get( '/inc' )
         .set( 'Connection', 'close' )
         .end( ( err, res ) => {
            expect( res.text ).to.be.equal( '1' )
            done()
         } )
   } ),

   it( 'should respond 1', ( done ) => {
      chai.request( server )
         .get( '/inc' )
         .set( 'Connection', 'close' )
         .end( ( err, res ) => {
            expect( res.text ).to.be.equal( '1' )
            done()
         } )
   } )
} )

测试失败,因为服务器在第一次测试后没有运行。请注意,在after_each 部分中,我强制清除缓存以完全丢失最后一个服务器实例。如果运行单个测试用例,则测试成功:

first test group
    ✓ should respond 1
    1) "after each" hook for "should respond 1"


  1 passing (70ms)
  1 failing

  1) first test group
       "after each" hook for "should respond 1":
     Error: Not running
      at Server.close (net.js:1620:12)
      at emitCloseNT (net.js:1671:8)
      at _combinedTickCallback (internal/process/next_tick.js:135:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

我使用的配置:

  • 节点 8.11.1
  • 快递:“4.16.3”
  • 摩卡5.0.5
  • 柴4.1.2
  • chai-http 4.0.0

我该如何解决这个问题?错误信息是什么意思?

【问题讨论】:

  • 通常,测试是使用 Web 服务器代理而不是服务器完成的。有什么理由不能像supertest 那样为express 使用代理?
  • 我认为我正在使用代理,在我的情况下应该是 chai-http 不是吗?
  • 在 afterEach 中,您正在破坏服务器,很可能在服务器再次启动之前,第二个测试已运行。 1. 在运行第二个测试之前尝试使用超时。 2. 在 const chaiHttp = chai.request(app).keepOpen() 中使用 keepOpen(此行来自 chai-http 文档)以保持服务器打开。在任何情况下,删除 afterEach 块和 .set('connection',close) 行,因为它们对您的测试没有任何用处

标签: node.js express mocha.js chai chai-http


【解决方案1】:

稍加修改即可使用 我没有使用server-destroy,因为server.close 工作得很好

server.js

// ( function() { // no need for this
   'use strict'

   //const enableDestroy = require( 'server-destroy' )
   const app = require( 'express' )()
   const http = require( 'http' )

   let val = 0

   app.use( '/inc', (req, res) => {
      val ++
      res.send(val.toString())
   } )

   const server = http.createServer( app )

   server.listen( 3000 )

   // enableDestroy(server);    
   module.exports = server

// } )()

test.js

const chai = require( 'chai' )
const chaiHttp = require( 'chai-http' )
const expect = chai.expect
chai.use( chaiHttp )

let server

describe( 'first test group', () => {
   beforeEach( () => {
      server = require( './server' )
   } ),

   afterEach( ( done ) => {

      // UPDATE DON'T CLOSE THE SERVER

      delete require.cache[require.resolve( './server' )]
      done()

      //server.close( () => {
      //   delete require.cache[require.resolve( './server' )]
      //   done()
      //})      
   } ),

   it( 'should respond 1', ( done ) => {
      chai.request( server )
         .get( '/inc' )
         .set( 'Connection', 'close' )
         .end( ( err, res ) => {
            expect( res.text ).to.be.equal( '1' )
            done()
         } )
   } ),

   it( 'should respond 1', ( done ) => {
      chai.request( server )
         .get( '/inc' )
         .set( 'Connection', 'close' )
         .end( ( err, res ) => {
            expect( res.text ).to.be.equal( '1' )
            done()
         } )
   } )
} )

【讨论】:

  • 谢谢!这项工作我给你一个赞成票,但我认为这不是正确的解决方案:你传递给 close 的 cb 忽略了参数(在这种情况下是错误)。您可以检查简单地记录传递给关闭 cb 的参数:这里仍然存在错误! server.close( (arg) => { console.log( arg ) delete require.cache[require.resolve( './server' )] done() })
  • 你是对的,所以我更新了我的代码。不要打电话给server.close。服务器将自动关闭,但我不知道为什么。您可以通过在 server.js 文件中添加此行 server.on( 'close', () => console.log('Closing') ) 来检查它是否正在关闭。
  • 是的,没错!似乎有人为我关闭了服务器,因此不再需要手动关闭服务器,但如果您想刷新服务器实例,仍然需要删除缓存!所以如果你用这个消息更新你的回复,我会接受它!
【解决方案2】:

这是在最初的问题之后的一段时间。

在 chai-http 文档中,我可以发现它具有使用请求方法中的 keepOpen() 方法打开服务器连接的机制。 (实际上它返回了一个代理)

const chai = require("chai");
const chaiHttp = require("chai-http");

chai.use(chaiHttp);

const chaiAppServer = chai.request(server).keepOpen();

https://www.chaijs.com/plugins/chai-http/#integration-testing

但正如它所提到的,我们必须手动关闭服务器连接。

describe("TEST Case group", () => {

    after(() => {
        chaiAppServer.close();
    });

    //..... integration test cases

});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-05
    • 2014-12-21
    • 1970-01-01
    • 2022-06-20
    • 2016-11-15
    • 2015-11-06
    • 1970-01-01
    相关资源
    最近更新 更多