如何在每个测试的基础上更改模拟实现?
2022-08-30 01:24:40
我想通过扩展默认模拟的行为并在执行下一个测试时将其恢复为原始实现,在每个测试的基础上更改模拟依赖项的实现。
更簡單地說,這是我試圖實現的:
- 模拟依赖关系
- 在单个测试中更改/扩展模拟实现
- 执行下一个测试时恢复为原始模拟
我目前正在使用Jest v21。以下是典型测试的样子:
// __mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
// __tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
以下是我到目前为止尝试过的方法:
-
mockFn.mockImplementationOnce(fn)
it('should override myModule.b mock result (and leave the other methods untouched)', () => { myMockedModule.b.mockImplementationOnce(() => 'overridden'); myModule.a(); // === true myModule.b(); // === 'overridden' });
优点
- 首次调用后恢复到原始实现
缺点
- 如果测试多次调用,它将中断
b
- 它不会恢复到原始实现,直到不被调用(在下一个测试中泄漏)
b
-
jest.doMock(moduleName, factory, options)
it('should override myModule.b mock result (and leave the other methods untouched)', () => { jest.doMock('../myModule', () => { return { a: jest.fn(() => true, b: jest.fn(() => 'overridden', } }); myModule.a(); // === true myModule.b(); // === 'overridden' });
优点
- 在每次测试中显式重新模拟
缺点
- 无法为所有测试定义默认模拟实现
- 无法扩展默认实现,强制重新声明每个模拟方法
-
使用 setter 方法进行手动模拟(如此处所述)
// __mocks__/myModule.js const myMockedModule = jest.genMockFromModule('../myModule'); let a = true; let b = true; myMockedModule.a = jest.fn(() => a); myMockedModule.b = jest.fn(() => b); myMockedModule.__setA = (value) => { a = value }; myMockedModule.__setB = (value) => { b = value }; myMockedModule.__reset = () => { a = true; b = true; }; export default myMockedModule;
// __tests__/myTest.js it('should override myModule.b mock result (and leave the other methods untouched)', () => { myModule.__setB('overridden'); myModule.a(); // === true myModule.b(); // === 'overridden' myModule.__reset(); });
优点
- 完全控制模拟结果
缺点
- 大量样板代码
- 难以长期维持
-
jest.spyOn(object, methodName)
beforeEach(() => { jest.clearAllMocks(); jest.restoreAllMocks(); }); // Mock myModule jest.mock('../myModule'); it('should override myModule.b mock result (and leave the other methods untouched)', () => { const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden'); myMockedModule.a(); // === true myMockedModule.b(); // === 'overridden' // How to get back to original mocked value? });
缺点
- 我无法恢复到原始模拟返回值,因此会影响下一个测试
mockImplementation
- 我无法恢复到原始模拟返回值,因此会影响下一个测试