javascript – 如何在每个测试的基础上更改模拟实现[Jestjs]
作者:互联网
我想通过扩展默认模拟的行为并在执行以下测试时将其还原回原始实现来更改每个测试基础上的模拟依赖项的实现.
更简单地说,这就是我想要实现的目标:
>模拟依赖
>在单个测试中更改/扩展模拟实现
>在下一次测试执行时恢复原始模拟
我目前正在使用Jest v21.
以下是典型的Jest测试:
__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 eeffects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
我尝试了一些策略,但我找不到任何可以定义令人满意的解决方案.
1 – mockFn.mockImplementationOnce(fn)
利弊
>在第一次调用后恢复到原始实现
缺点
>如果测试多次调用b,它将会中断
>它不会回复到
原始实现直到b没有被调用(泄漏出来的)
下次测试)
码:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
2 – 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'
});
3 – 使用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();
});
4 – jest.spyOn(object, methodName)
缺点
>我无法将mockImplementation还原为原始的模拟返回值,因此会影响以下测试
码:
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 the original mocked value?
});
提前感谢您的任何意见/建议!
解决方法:
编写测试的一个很好的模式是创建一个设置工厂函数,它返回测试当前模块所需的数据.
下面是您的第二个示例后面的一些示例代码,但允许以可重用的方式提供默认值和覆盖值.
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
return {
mockedModule: jest.doMock('../myModule', () => mockedFunctions)
}
}
it("should return true for module a", () => {
const { mockedModule } = setup();
expect(mockedModule.a()).toEqual(true)
});
it("should return override for module a", () => {
const EXPECTED_VALUE = "override"
const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
});
});
标签:javascript,unit-testing,mocking,jestjs 来源: https://codeday.me/bug/20190930/1836135.html