代码之家  ›  专栏  ›  技术社区  ›  Catfish

如何断言Ex'状态(200)。发送({ hello:‘Word’})’实际上用正确的数据发送了200?

  •  0
  • Catfish  · 技术社区  · 6 年前

    我想学习如何正确地对express端点进行单元测试,特别是处理程序代码,并在响应中断言正确的状态和数据。

    我想这么做 没有 supertest,因为我有一个带有一堆中间件函数的helper库,我想单独测试它们。

    对于这样一个简单的应用程序

    'use strict'
    
    const express = require('express')
    const app = express()
    const helloWorld = require('./helloWorld')
    
    app.get('/', helloWorld)
    
    app.listen(5000, () => console.log('we\'re up!'))
    

    使用这样一个简单的处理函数

    'use strict'
    
    function helloWorld (req, res, next) {
      const data = {
        hello: 'world'
      }
      res.status(200).send(data)
    }
    
    module.exports = helloWorld
    

    我正在做这个测试

    'use strict'
    const helloWorld = require('./helloWorld')
    
    describe('#helloWorld', () => {
      it('should return 200', () => {
        const req = {
    
        }
    
        const res = {
          status: function (code) {
            this.statusCode = code
            return this
          },
          send: function () {
            return this
          }
        }
    
        const next = () => {}
    
        helloWorld(req, res, next)
        // TODO: How to assert status was 200 and data sent was { hello: 'world' }?
      })
    })
    

    如何断言200的状态和数据 { hello: 'world' } ?

    更新 这是可行的,但是如果这样做是个糟糕的主意的话。

    更新测试

    'use strict'
    
    const { expect } = require('chai')
    const helloWorld = require('./helloWorld')
    
    describe('#helloWorld', () => {
      it('should return 200', () => {
        const req = {
    
        }
    
        const res = {
          _status: null,
          _json: null,
          status: function (code) {
            this._status = code
            return this
          },
          send: function (json) {
            this._json = json
            return this
          }
        }
    
        const next = () => {}
    
        helloWorld(req, res, next)
        expect(res._status).to.equal(200)
        expect(res._json.hello).to.equal('world')
      })
    })
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   joshuakcockrell    6 年前

    自从 res.status() res.send() 实际上是在调用较低级别的node.js http 方法,这里没有更多的内联测试,你可以在这里做。这些快递方法多年来一直在大公司和小公司的几个大生产环境中进行过测试,所以你可以相信他们会做好自己的工作。

    一个更有用的测试可能是确保您的服务器完全用正确的响应响应。你所能做的就是创造一个独立的 test-server.js 归档并使用 request 通过多个测试访问服务器的库 localhost:port . 这将模拟客户端与服务器的交互。

    const request = require('request');
    const assert = require('assert');
    
    // Example test
    request('http://localhost:8080', (err, res, body) => {
    
      // Run your tests here
      assert.strictEqual(body.hello, 'world');
      assert.strictEqual(res.statusCode, 200);
      // .. etc
    });
    

    然后您可以运行您的 测试服务器.js 每次对服务器进行更改以进行测试时,都将其归档。

        2
  •  0
  •   James    6 年前

    您需要引入一个mocking/stubing库(我个人倾向于使用 Sinon )嘲笑 res 对象例如

    // Setup stubs
    const req = {};
    const res = {
       status() {},
       send() {}
    };
    const next = () => {}
    // Setup mock
    const resMock = sinon.mock(res);
    resMock.expects('status').once().withArgs(200);
    resMock.expects('send').once().withArgs({ hello: 'world' });
    // Invoke code with mock
    helloWorld(req, resMock, next);
    // Assert expectations
    resMock.verify();
    

    您也可以使用存根或间谍,用于多功能断言,虽然我发现模拟更适合安装。

    同样的例子使用间谍而不是模仿

    // Setup stubs
    const req = {};
    const res = {
      status() {},
      send() {}
    };
    const next = () => {};
    // Setup spies
    const statusSpy = sinon.spy(res, 'status');
    const sendSpy = sinon.spy(res, 'send');
    // Invoke code
    helloWorld(req, res, next);
    // Assert calls 
    expect(statusSpy.calledOnceWith(200)).to.be.true;
    expect(sendSpy.calledWithMatch({ hello: 'world' })).to.be.true;
    

    如果这是许多测试的共同趋势,那么你可以像

    const req = {};
    const res = {
      status() {},
      send() {}
    };
    const next = () => {};
    ...
    before(() => {
      // Setup spies once for test suite
      sinon.spy(res, 'status');
      sinon.spy(res, 'send');
    })
    
    it('should return 200', () => {
      helloWorld(res, res, next);
      expect(res.status.calledOnceWith(200)).to.be.true;
      expect(res.send.calledWithMatch({ hello: 'world' })).to.be.true;
    })
    
    afterEach(() => {
      // reset spies after each test
      res.status.resetHistory();
      res.send.resetHistory();
    })