如何在node.js应用程序中对控制器进行单元测试?

时间:2020-06-23 13:46:29

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

我正在为我的node.js应用程序使用fastify框架,并将其序列化为ORM。我正在使用mocha,chai和Sinon进行单元测试。我必须对控制器功能进行单元测试。以下是示例控制器功能。

// controllers.js;

const service = require('../services');

exports.create = (req, reply) => {
  const attributes = req.body;
  service.create(attributes)
    .then((result) => {
      reply.code(201).send(result);
    })
    .catch((error) => {
      reply.send(error);
    });
};

我的服务文件如下,

// services.js;

const { Model } = require('../models');

function create(attributes) {
  return Model.create(attributes);
}

module.exports = { create };

在上面的代码中,我只想对controllers.js中的“ create”功能进行单元测试。问题是,它不应调用数据库,因为它是单元测试。但是service.js文件中的Model.create将调用数据库。我该如何仅对测试控制器功能进行单元化?

1 个答案:

答案 0 :(得分:1)

您应该对service.create方法进行存根并创建模拟的reqreply对象。

例如

controller.js

const service = require('./service');

exports.create = (req, reply) => {
  const attributes = req.body;
  service
    .create(attributes)
    .then((result) => {
      reply.code(201).send(result);
    })
    .catch((error) => {
      reply.send(error);
    });
};

service.js

const { Model } = require('./models');

function create(attributes) {
  return Model.create(attributes);
}

module.exports = { create };

models.js

const Model = {
  create() {
    console.log('real implementation');
  },
};

module.exports = { Model };

controller.test.js

const controller = require('./controller');
const service = require('./service');
const sinon = require('sinon');

const flushPromises = () => new Promise(setImmediate);

describe('62536251', () => {
  afterEach(() => {
    sinon.restore();
  });
  it('should create', async () => {
    const mResult = 'success';
    sinon.stub(service, 'create').resolves(mResult);
    const mReq = { body: {} };
    const mReply = { code: sinon.stub().returnsThis(), send: sinon.stub() };
    controller.create(mReq, mReply);
    await flushPromises();
    sinon.assert.calledWith(mReply.code, 201);
    sinon.assert.calledWith(mReply.send, 'success');
  });

  it('should handle error', async () => {
    const mError = new Error('network');
    sinon.stub(service, 'create').rejects(mError);
    const mReq = { body: {} };
    const mReply = { code: sinon.stub().returnsThis(), send: sinon.stub() };
    controller.create(mReq, mReply);
    await flushPromises();
    sinon.assert.calledWith(mReply.send, mError);
  });
});

具有覆盖率报告的单元测试结果:

  62536251
    ✓ should create
    ✓ should handle error


  2 passing (13ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   83.33 |      100 |      60 |   83.33 |                   
 controller.js |     100 |      100 |     100 |     100 |                   
 models.js     |   66.67 |      100 |       0 |   66.67 | 3                 
 service.js    |   66.67 |      100 |       0 |   66.67 | 4                 
---------------|---------|----------|---------|---------|-------------------
相关问题