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

Node.js 如何使用Jest编写Express控制器的单元测试?,node.js,unit-testing,express,jestjs,Node.js,Unit Testing,Express,Jestjs,感谢您抽出时间阅读我的问题 我对这方面的玩笑和单元测试还很陌生,所以在我开始为我的控制器函数编写单元测试之前,我想检查一下我的理解。如此高的层次,我理解单元测试是测试控制器函数在调用时是否按预期运行 我将如何着手为以下代码编写Jest单元测试?我非常希望能有一个示例,以便在为其他控制器编写jest测试时参考它。多谢各位 //retrieveMember.js const debug = require('debug')('get_member'); const MemberService =

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

我对这方面的玩笑和单元测试还很陌生,所以在我开始为我的控制器函数编写单元测试之前,我想检查一下我的理解。如此高的层次,我理解单元测试是测试控制器函数在调用时是否按预期运行

我将如何着手为以下代码编写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;

以下是单元测试解决方案:

retrieveMember.js

const debug=console.debug;
const MemberService=require('./MemberService');
const generateError=require('./generateError');
const retrieveMember=async(请求、恢复、下一步)=>{
试一试{
如果(req.params.id==''|| req.params.id===未定义){
抛出generateError(400,“无效”);
}
常量regex=RegExp(“[^a-zA-Z0-9-]”);
if(正则表达式测试(要求参数id)){
抛出generateError(400,“无效格式”);
}
常量memberId=req.params.id;
const memberRecord=等待MemberService.retrieveOneMember(memberId);
常量成员详细信息={
id:memberRecord.id,
用户名:memberRecord.username,
};
res.status(200).send({member\u detail:member\u detail});
}捕获(e){
如果(e){
调试('无法获取成员');
返回下一个(e);
}
}
};
module.exports=检索成员;
MemberService.js

const MemberService={
异步retrieveOneMember(){
返回“真实数据”;
},
};
module.exports=成员服务;
generateError.js

函数生成器错误(状态、消息){
返回新的错误(消息);
}
module.exports=generateError;
retrieveMember.test.js

const retrieveMember=require('./retrieveMember');
const MemberService=require('./MemberService');
描述('61834610',()=>{
它('如果id为空字符串,则应抛出400错误',异步()=>{
const mReq={params:{id:'}};
常数mRes={};
const mNext=jest.fn();
等待检索成员(mReq、mRes、mNext);
期望(mNext).toBeCalledWith(新错误('invalid');
});
它('如果id未定义,则应抛出400错误',异步()=>{
const mReq={params:{};
常数mRes={};
const mNext=jest.fn();
等待检索成员(mReq、mRes、mNext);
期望(mNext).toBeCalledWith(新错误('invalid');
});
它('如果id格式无效,则应抛出400错误',异步()=>{
const mReq={params:{id:'$$'};
常数mRes={};
const mNext=jest.fn();
等待检索成员(mReq、mRes、mNext);
期望(mNext).toBeCalledWith(新错误('invalid format');
});
它('应该按id检索一个成员并正确发送响应',async()=>{
const mMemberRecord={id:'1',用户名:'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();
等待检索成员(mReq、mRes、mNext);
expect(MemberService.retrieveOneMember).toBeCalledWith('1');
预期(mRes.状态)。与(200)一起调用;
expect(mRes.send).toBeCalledWith({member_detail:{id:'1',username:'KF1'}});
});
});
单元测试结果和覆盖率报告:

PASS stackoverflow/61834610/retrieveMember.test.js(9.346s)
61834610
✓ 如果id为空字符串(18ms),则应抛出400错误
✓ 如果id未定义,则应抛出400错误(2ms)
✓ 如果id为无效格式(1ms),则应抛出400错误
✓ 应按id检索一个成员并正确发送响应(1ms)
console.debug
无法获取成员
在stackoverflow/61834610/retrieveMember.js:27:7
console.debug
无法获取成员
在stackoverflow/61834610/retrieveMember.js:27:7
console.debug
无法获取成员
在stackoverflow/61834610/retrieveMember.js:27:7
-------------------|---------|----------|---------|---------|-------------------
文件|%Stmts |%Branch |%Funcs |%Line |未覆盖行|s
-------------------|---------|----------|---------|---------|-------------------
所有文件| 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
-------------------|---------|----------|---------|---------|-------------------
测试套件:1个通过,共1个
测试:4次通过,共4次
快照:共0个
时间:10.539秒

谢谢!非常感谢您的回复。实际上,我正在使用typescript并导出默认的MemberService,因此我不得不使用
MemberService.default
而不是
MemberService
作为函数
jest.spyOn()
expect()
的参数。我不熟悉
.mockReturnThis()
,但现在知道它应该用于通常被链接的方法(因此总是需要返回它)。@surferwat Yes
.mockReturnThis()
将返回
this
上下文,以便您可以链接调用方法。