如何使用Jest编写Express控制器的单元测试?

时间:2020-05-16 09:26:34

标签: node.js unit-testing express jestjs

感谢您抽出宝贵时间阅读我的问题。

在这方面,我对Jest和单元测试非常陌生,因此在开始为控制器功能编写单元测试之前,我想检查一下自己的理解。如此高的层次,我知道单元测试是为了测试控制器函数在调用时是否表现出预期的效果。

如何为以下代码编写Jest单元测试?我会很感激一个示例,以便在编写其他控制器的测试时可以参考该示例。谢谢。

//retrieveMember.js


const debug = require('debug')('get_member');
const MemberService = require('../services/MemberService');
const generateError = require('../lib/generateError');


const retrieveMember = async (req, res, next) => {
  try {
    if (req.params.id === ""
    || req.params.id === undefined) {
      throw generateError(400, "invalid.");
    }

    const regex = RegExp("[^a-zA-Z0-9\-]");
    if (regex.test(req.params.id)) {
      throw generateError(400, "invalid format.");
    }

    const memberId = req.params.id;
    const memberRecord = await MemberService.retrieveOneMember(memberId);

    const member_detail = {
      id: memberRecord.id,
      username: memberRecord.username,
    };

    res.status(200).send({member_detail: member_detail});
  } catch (e) {
    if (e) {
      debug('could not get member');
      return next(e);
    }
  }
};


module.exports = retrieveMember;

1 个答案:

答案 0 :(得分:1)

这是单元测试解决方案:

retrieveMember.js

const debug = console.debug;
const MemberService = require('./MemberService');
const generateError = require('./generateError');

const retrieveMember = async (req, res, next) => {
  try {
    if (req.params.id === '' || req.params.id === undefined) {
      throw generateError(400, 'invalid.');
    }

    const regex = RegExp('[^a-zA-Z0-9-]');
    if (regex.test(req.params.id)) {
      throw generateError(400, 'invalid format.');
    }

    const memberId = req.params.id;
    const memberRecord = await MemberService.retrieveOneMember(memberId);

    const member_detail = {
      id: memberRecord.id,
      username: memberRecord.username,
    };

    res.status(200).send({ member_detail: member_detail });
  } catch (e) {
    if (e) {
      debug('could not get member');
      return next(e);
    }
  }
};

module.exports = retrieveMember;

MemberService.js

const MemberService = {
  async retrieveOneMember() {
    return 'real data';
  },
};

module.exports = MemberService;

generateError.js

function generateError(status, message) {
  return new Error(message);
}

module.exports = generateError;

retrieveMember.test.js

const retrieveMember = require('./retrieveMember');
const MemberService = require('./MemberService');

describe('61834610', () => {
  it('should throw 400 error if id is empty string', async () => {
    const mReq = { params: { id: '' } };
    const mRes = {};
    const mNext = jest.fn();
    await retrieveMember(mReq, mRes, mNext);
    expect(mNext).toBeCalledWith(new Error('invalid.'));
  });

  it('should throw 400 error if id is undefined', async () => {
    const mReq = { params: {} };
    const mRes = {};
    const mNext = jest.fn();
    await retrieveMember(mReq, mRes, mNext);
    expect(mNext).toBeCalledWith(new Error('invalid.'));
  });

  it('should throw 400 error if id is invalid format', async () => {
    const mReq = { params: { id: '$$' } };
    const mRes = {};
    const mNext = jest.fn();
    await retrieveMember(mReq, mRes, mNext);
    expect(mNext).toBeCalledWith(new Error('invalid format.'));
  });

  it('should retrieve one member by id and send response correctly', async () => {
    const mMemberRecord = { id: '1', username: 'KF1' };
    jest.spyOn(MemberService, 'retrieveOneMember').mockResolvedValueOnce(mMemberRecord);
    const mReq = { params: { id: '1' } };
    const mRes = { status: jest.fn().mockReturnThis(), send: jest.fn() };
    const mNext = jest.fn();
    await retrieveMember(mReq, mRes, mNext);
    expect(MemberService.retrieveOneMember).toBeCalledWith('1');
    expect(mRes.status).toBeCalledWith(200);
    expect(mRes.send).toBeCalledWith({ member_detail: { id: '1', username: 'KF1' } });
  });
});

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

 PASS  stackoverflow/61834610/retrieveMember.test.js (9.346s)
  61834610
    ✓ should throw 400 error if id is empty string (18ms)
    ✓ should throw 400 error if id is undefined (2ms)
    ✓ should throw 400 error if id is invalid format (1ms)
    ✓ should retrieve one member by id and send response correctly (1ms)

  console.debug
    could not get member

      at stackoverflow/61834610/retrieveMember.js:27:7

  console.debug
    could not get member

      at stackoverflow/61834610/retrieveMember.js:27:7

  console.debug
    could not get member

      at stackoverflow/61834610/retrieveMember.js:27:7

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   95.83 |     87.5 |      75 |   95.45 |                   
 MemberService.js  |   66.67 |      100 |       0 |   66.67 | 3                 
 generateError.js  |     100 |      100 |     100 |     100 |                   
 retrieveMember.js |     100 |     87.5 |     100 |     100 | 26                
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        10.539s