因此,我试图找出模拟函数请求和响应的最佳方法,我看到了许多方法,有些使用jest.fn()
,有些使用sinon,还有一些使用外部包。
当想要返回状态、json以及请求的内容时,最好的方法是什么?请参阅下面的代码。
export const redisGet = (client) => async (req, res, next) => {
try {
const {
postCode,
houseNumber,
} = req.params
const addressObj = {
postCode,
houseNumber,
}
const addressGetParams = JSON.stringify(addressObj)
await client.get(addressGetParams, (err, data) => {
if (data) {
return res.status(200).send({
error: false,
message: `Addresses found.`,
data: JSON.parse(data)
})
}
if (err) {
return res.status(400).send({
error: err,
message: `Bad request`,
data: JSON.parse(data),
})
}
next()
})
} catch (e) {
throw Error(e)
}
}
jestjs
和sinonjs
都可以模拟/存根模块。选择其中一个就足够了。下面是一个使用jestjs
的示例。单元测试解决方案:
index.ts
:
export const redisGet = (client) => async (req, res, next) => {
try {
const { postCode, houseNumber } = req.params;
const addressObj = { postCode, houseNumber };
const addressGetParams = JSON.stringify(addressObj);
client.get(addressGetParams, (err, data) => {
if (data) {
return res.status(200).send({
error: false,
message: `Addresses found.`,
data: JSON.parse(data),
});
}
if (err) {
return res.status(400).send({
error: err,
message: `Bad request`,
});
}
next();
});
} catch (e) {
throw Error(e);
}
};
index.test.ts
:
import { redisGet } from './';
describe('63253476', () => {
it('should found addresses', async () => {
const mClient = {
get: jest.fn().mockImplementationOnce((params, callback) => {
callback(null, '{"id": 1}');
}),
};
const mReq = { params: { postCode: 123, houseNumber: 456 } };
const mRes = { status: jest.fn().mockReturnThis(), send: jest.fn() };
const mNext = jest.fn();
await redisGet(mClient)(mReq, mRes, mNext);
expect(mClient.get).toBeCalledWith(JSON.stringify({ postCode: 123, houseNumber: 456 }), expect.any(Function));
expect(mRes.status).toBeCalledWith(200);
expect(mRes.send).toBeCalledWith({ error: false, message: `Addresses found.`, data: { id: 1 } });
expect(mNext).not.toBeCalled();
});
it('should handle error', async () => {
const mErr = new Error('timeout');
const mClient = {
get: jest.fn().mockImplementationOnce((params, callback) => {
callback(mErr);
}),
};
const mReq = { params: { postCode: 123, houseNumber: 456 } };
const mRes = { status: jest.fn().mockReturnThis(), send: jest.fn() };
const mNext = jest.fn();
await redisGet(mClient)(mReq, mRes, mNext);
expect(mClient.get).toBeCalledWith(JSON.stringify({ postCode: 123, houseNumber: 456 }), expect.any(Function));
expect(mRes.status).toBeCalledWith(400);
expect(mRes.send).toBeCalledWith({ error: mErr, message: `Bad request` });
expect(mNext).not.toBeCalled();
});
it('should do nothing and call next middleware', async () => {
const mClient = {
get: jest.fn().mockImplementationOnce((params, callback) => {
callback();
}),
};
const mReq = { params: { postCode: 123, houseNumber: 456 } };
const mRes = { status: jest.fn().mockReturnThis(), send: jest.fn() };
const mNext = jest.fn();
await redisGet(mClient)(mReq, mRes, mNext);
expect(mClient.get).toBeCalledWith(JSON.stringify({ postCode: 123, houseNumber: 456 }), expect.any(Function));
expect(mRes.status).not.toBeCalled();
expect(mRes.send).not.toBeCalled();
expect(mNext).toBeCalled();
});
});
带覆盖率报告的单元测试结果:
PASS src/stackoverflow/63253476/index.test.ts (11.338s)
63253476
✓ should found addresses (8ms)
✓ should handle error (2ms)
✓ should do nothing and call next middleware (2ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 92.86 | 100 | 100 | 91.67 | |
index.ts | 92.86 | 100 | 100 | 91.67 | 26 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 13.824s