我想通过扩展默认模拟的行为并在下一次测试执行时将其恢复为原始实现来更改基于单个测试的模拟依赖项的实现。
更简单地说,这就是我要实现的目标:
- 模拟依赖
- 在单个测试中更改/扩展模拟实现
- 在下一次测试执行时恢复到原始模拟
我目前正在使用 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 方法手动模拟(如 here 所述)
// __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
还原为原始的模拟返回值,因此会影响下一次测试
- 我无法将
最佳答案
使用mockFn.mockImplementation(fn) .
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
// (funcToMock as jest.Mock)... in TS
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// (funcToMock as jest.Mock)... in TS
// ...
});
关于javascript - 如何在单个测试的基础上更改模拟实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48790927/