我试图用Jest编写单元测试,以利用moment.js库模拟代码的几个部分。为了完整起见,这是一个Node + Express项目,用TypeScript编写,带有支持的moment.d.ts
文件。
我要测试的导入和代码块:
import moment from 'moment';
const durationSinceLastEmail = moment.duration(moment(new Date())
.diff(moment(user.passwordRecoveryTokenRequestDate)));
为导入的弯矩参考提供的类型信息列出了两个实际项目:
(alias) function moment(inp?: moment.MomentInput, format?: moment.MomentFormatSpecification, strict?: boolean): moment.Moment (+1 overload)
(alias) namespace moment
import moment
我的实现代码使用两种形式:moment.duration
用于名称空间,moment(...params)
用于函数。
我一般的Jest模拟策略不是很有效。例)
jest.mock('moment', () => {
return jest.fn().mockImplementation( () => {
return {
duration: (...params) => mockDuration(...params)
};
});
});
通过以一种更有力的方式直接替换duration方法,我成功地模拟了duration函数。
const originalDuration: Function = moment.duration;
mockDuration.mockImplementation((...params) => {
const original = originalDuration(...params);
// Apply mocks on returning object here
// or supply entirely new mock object
return original;
});
moment.duration = mockDuration;
坦率地说,代码相当粗糙,但是它使我半途而废,因为这使我可以捕获对moment.duration(...params)
的调用,但是我尝试模拟moment(...)
调用的每种方法都具有要么不起作用,要么与上面的方法完全冲突(并且也不起作用)。
命名冲突似乎是我遇到问题的根源,所以我的问题是:
1)无论如何,我是否有必要将这些不同的引用分开,以便可以对其进行明确处理?
或
2)是否有一种有效的方法可以分别模拟它们,或者在单个模拟对象中同时为函数和名称空间提供模拟?
答案 0 :(得分:1)
您可以为moment
创建一个Manual Mock,并为其提供所需的任何实现。
在项目的根目录下__mocks__/moment.js
旁边创建node_modules
:
const momentMock = jest.fn(); // create the moment mock
momentMock.mockImplementation(() => ({ diff: jest.fn() })); // give it a mock implementation
momentMock.duration = jest.fn(); // add the moment.duration mock
export default momentMock; // export the mock
在测试中调用jest.mock('moment');
以使用模拟:
import moment from 'moment';
jest.mock('moment'); // use the mock
test('durationSinceLastEmail', () => {
const user = {
passwordRecoveryTokenRequestDate: new Date('2019-01-01')
}
const durationSinceLastEmail = moment.duration(moment(new Date())
.diff(moment(user.passwordRecoveryTokenRequestDate)));
expect(moment).toHaveBeenCalledTimes(2); // SUCCESS
expect(moment.duration).toHaveBeenCalledTimes(1); // SUCCESS
});