node.js - 使用 Jest 在 Nodejs 中进行单元测试
问题描述
我在控制器中有一个方法,如下所示:
import { calcu } from '../services/myServices';
export const getProduct = (req, res, next) => {
try {
const { type } = req.params;
const { id, productCode } = req.body;
if (!id || !productCode) {
res.status(400).json({ error: { message: 'Id or productCode is required' } });
} else {
switch (type.toUpperCase()) {
case 'X':
try {
const result = calcu(id, productCode);
res.status(200).json(result);
} catch (err) {
res.status(400).json({ error: { message: err.message } });
}
break;
default:
res.status(400).json({ error: { message: `type ${type} is not support` } });
}
}
} catch (err) {
next(err);
}
};
在这种情况下,这是我的单元测试代码:
import { getProduct } from './quotationController';
describe('Controller', () => {
let json, res, status;
test('Should return message error if the id or productCode is missing', () => {
const req = {
body: { id: "1111" },
param: { type: "qqqqq" }
};
const next = err => err.message;
const result = getProduct(req, res, next);
//expect(result).toBe(undefined);
expect(result).toEqual({
code: 400,
message: 'Id or productCode is required'
});
});
})
运行单元测试代码时出现错误:
结果未定义。
解决方案
这是单元测试解决方案:
controller.js
:
import { calcu } from './service';
export const getProduct = (req, res, next) => {
try {
const { type } = req.params;
const { id, productCode } = req.body;
if (!id || !productCode) {
res.status(400).json({ error: { message: 'Id or productCode is required' } });
} else {
switch (type.toUpperCase()) {
case 'X':
try {
const result = calcu(id, productCode);
res.status(200).json(result);
} catch (err) {
res.status(400).json({ error: { message: err.message } });
}
break;
default:
res.status(400).json({ error: { message: `type ${type} is not support` } });
}
}
} catch (err) {
next(err);
}
};
service.js
:(模拟)
export function calcu(id, code) {
return id + code;
}
controller.test.js
:
import { getProduct } from './controller';
import { calcu } from './service';
jest.mock('./service.js', () => ({ calcu: jest.fn() }));
describe('Controller', () => {
let mRes;
let mNext;
beforeEach(() => {
mRes = { status: jest.fn().mockReturnThis(), json: jest.fn() };
mNext = jest.fn();
});
afterEach(() => {
jest.resetAllMocks();
});
test('Should return message error if the id or productCode is missing', () => {
const mReq = { body: { id: '1111' }, params: { type: 'qqqqq' } };
getProduct(mReq, mRes, mNext);
expect(mRes.status).toBeCalledWith(400);
expect(mRes.status().json).toBeCalledWith({ error: { message: 'Id or productCode is required' } });
});
test('should call next when error happens', () => {
const mReq = {};
getProduct(mReq, mRes, mNext);
expect(mNext).toBeCalledWith(expect.any(Error));
});
test('should return message error if type is not support', () => {
const mReq = { params: { type: 'qqqqq' }, body: { id: '1111', productCode: '22' } };
getProduct(mReq, mRes, mNext);
expect(mRes.status).toBeCalledWith(400);
expect(mRes.status().json).toBeCalledWith({ error: { message: `type ${mReq.params.type} is not support` } });
});
test('should return message error if calcu errors', () => {
const mReq = { params: { type: 'x' }, body: { id: '1111', productCode: '22' } };
const mError = new Error('calc error');
calcu.mockImplementationOnce(() => {
throw mError;
});
getProduct(mReq, mRes, mNext);
expect(calcu).toBeCalledWith('1111', '22');
expect(mRes.status).toBeCalledWith(400);
expect(mRes.status().json).toBeCalledWith({ error: { message: mError.message } });
});
test('should return correct calc result', () => {
const mReq = { params: { type: 'x' }, body: { id: '1111', productCode: '22' } };
calcu.mockReturnValueOnce({ data: 'fake data' });
getProduct(mReq, mRes, mNext);
expect(calcu).toBeCalledWith('1111', '22');
expect(mRes.status).toBeCalledWith(200);
expect(mRes.status().json).toBeCalledWith({ data: 'fake data' });
});
});
覆盖率 100% 的单元测试结果:
PASS src/stackoverflow/59508494/controller.test.js (7.379s)
Controller
✓ Should return message error if the id or productCode is missing (6ms)
✓ should call next when error happens (1ms)
✓ should return message error if type is not support (1ms)
✓ should return message error if calcu errors (2ms)
✓ should return correct calc result (2ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
controller.js | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 8.731s, estimated 10s
源代码:https ://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59508494
推荐阅读
- less - 如何使用 customize-cra(2.x) 配置 Create-react-app 少模块?
- java - 尝试 catch 块后无法测试无法访问的返回语句
- verilog - 为仿真和综合定义不同的参数值
- delphi - TStringList 没有传递值
- python - 不同大小的numpy数组的减法
- javascript - 无法在 ReactJS 中更新状态
- jquery - JQuery:通过数据属性 LESS 从选择中删除选项
- racket - 在多个通道上同步/选择-evt(在运行时确定的数量)
- ios - 在 Xcode 11.3 故事板和笔尖大小几乎是两倍
- vue.js - 渲染错误:materialui 中的“TypeError:无法读取未定义的属性‘smAndDown’”