Sinon存根被跳过作为节点表达中间件

时间:2018-12-19 14:03:21

标签: node.js unit-testing mocha sinon chai

我正在尝试测试特定路线的行为。即使我创建存根,它也会继续运行中间件。我希望事件认证暂时通过。我了解到,这并不是真正的“单元”测试。我快到那里了。我还简化了代码。这是要测试的代码:

const { rejectUnauthenticated } = require('../modules/event-authentication.middleware');

router.get('/event', rejectUnauthenticated, (req, res) => {
  res.sendStatus(200);
});

这是我要跳过的中间件:

const rejectUnauthenticated = async (req, res, next) => {
  const { secretKey } = req.query;
  if (secretKey) {
    next();
  } else {
    res.status(403).send('Forbidden. Must include Secret Key for Event.');
  }
};

module.exports = {
  rejectUnauthenticated,
};

测试文件:

const chai = require('chai');
const chaiHttp = require('chai-http');
const sinon = require('sinon');
let app;
const authenticationMiddleware = require('../server/modules/event-authentication.middleware');

const { expect } = chai;
chai.use(chaiHttp);

describe('with correct secret key', () => {
  it('should return bracket', (done) => {
    sinon.stub(authenticationMiddleware, 'rejectUnauthenticated')
      .callsFake(async (req, res, next) => next());

    app = require('../server/server.js');

    chai.request(app)
      .get('/code-championship/registrant/event')
      .end((err, response) => {
        expect(response).to.have.status(200);
        authenticationMiddleware.rejectUnauthenticated.restore();
        done();
      });
  });
});

我已经尝试过其他类似的问题,例如:How to mock middleware in Express to skip authentication for unit test?和这样的问题:node express es6 sinon stubbing middleware not working,但是我仍然从中间件中获取403,应该跳过该问题。我还以调试模式运行了测试,因此我知道应该存根的中间件功能仍在运行。

存根我的代码是否有问题?这是ES6问题吗?

我可以重组代码或测试以使其正常工作吗?

2 个答案:

答案 0 :(得分:4)

存根代码确实存在问题。

当您需要服务器文件时

const app = require('../server/server.js');

您的应用是使用包括rejectUnauthenticated在内的整套中间件创建的,并且对中间件的引用存储在app中。

这样做的时候

sinon.stub(authenticationMiddleware, 'rejectUnauthenticated')
  .callsFake(async (req, res, next) => next());

您替换了rejectUnauthenticated模块的authenticationMiddleware导出方法,而不是对已经存储的原始rejectUnauthenticated的引用。

解决方案是在模拟已使用的中间件方法后,在 之后创建应用(即require('../server/server.js');):

const chai = require('chai');
const chaiHttp = require('chai-http');
const sinon = require('sinon');

// don't create app right away
let app;
const authenticationMiddleware = require('../server/modules/event-authentication.middleware');

const { expect } = chai;
chai.use(chaiHttp);

describe('with correct secret key', () => {
  it('should return bracket', (done) => {
    sinon.stub(authenticationMiddleware, 'rejectUnauthenticated')
      .callsFake(async (req, res, next) => next());

    // method is stubbed, you can create app now
    app = require('../server/server.js');

    chai.request(app)
      .get('/code-championship/registrant/event')
      .end((err, response) => {
        expect(response).to.have.status(200);
        authenticationMiddleware.rejectUnauthenticated.restore();
        done();
      });
  });
});

答案 1 :(得分:1)

根据@Sergey的建议,我确实切换到Jest。至少对于这种特定情况,它大大简化了实现。对于那些感兴趣的人,这是最终结果:

const express = require('express');
const request = require('supertest');
const registrantRouter = require('../server/routers/registrant.router');

jest.mock('../server/modules/event-authentication.middleware');
const { rejectUnauthenticated } = require('../server/modules/event-authentication.middleware');

const initRegistrantRouter = () => {
  const app = express();
  app.use(registrantRouter);
  return app;
};

describe('GET /registrant', () => {
  test('It should 200 if event authentication passes', async (done) => {
    const app = initRegistrantRouter();
    rejectUnauthenticated.mockImplementation((req, res, next) => next());
    const res = await request(app).get('/event');
    expect(res).toHaveProperty('status', 200);
    done();
  });
  test('It should 403 if event authentication fails', async (done) => {
    const app = initRegistrantRouter();
    rejectUnauthenticated.mockImplementation((req, res) => res.sendStatus(403));
    const res = await request(app).get('/event');
    expect(res).toHaveProperty('status', 403);
    done();
  });
});

也感谢这篇关于用Jest测试快速应用程序的有用博客文章:https://codewithhugo.com/testing-an-express-app-with-supertest-moxios-and-jest/