【发布时间】:2020-01-28 18:02:39
【问题描述】:
我正试图用 Jest 来理解以下内容:
resetAllMocks、resetModules、resetModuleRegistry 和 restoreAllMocks
我觉得很难。
我阅读了开玩笑的文档,但不太清楚。如果有人可以为我提供上述工作方式的示例并且它们彼此不同,我将不胜感激。
【问题讨论】:
标签: javascript unit-testing mocking jestjs
我正试图用 Jest 来理解以下内容:
resetAllMocks、resetModules、resetModuleRegistry 和 restoreAllMocks
我觉得很难。
我阅读了开玩笑的文档,但不太清楚。如果有人可以为我提供上述工作方式的示例并且它们彼此不同,我将不胜感激。
【问题讨论】:
标签: javascript unit-testing mocking jestjs
以下部分解释了每个函数的行为及其对应的配置指令。在配置指令的情况下,解释的行为发生在每个测试之间,使它们与其他测试越来越隔离。
对fn 的引用暗示了每个操作下的示例笑话模拟函数。
jest.clearAllMocks() 和 clearMocks:[boolean]
重置所有模拟使用数据,而不是它们的实现。换句话说,它只替换了一个玩笑模拟函数的fn.mock.calls 和fn.mock.instances 属性。
jest.resetAllMocks() 和 resetMocks:[boolean]
clearAllMocks() 的超集,它还负责将实现重置为 no return 函数。换句话说,它将用新的jest.fn() 替换模拟函数,而不仅仅是它的fn.mock.calls 和fn.mock.instances。
jest.restoreAllMocks() 和 restoreMocks:[boolean]
类似于resetAllMocks(),但有一个非常重要的区别。它恢复了“间谍”的原始实现。所以,它就像 “用 jest.fn() 替换模拟,但用它们的原始实现替换间谍”。
因此,如果我们使用 jest.fn()(不是间谍)手动分配事物,我们必须自己处理实现恢复,因为 jest 不会这样做。
jest.resetModules() 和 resetModules:[boolean]
它会重置 Jest 的模块注册表,该注册表是所有必需/导入模块的缓存。调用 this 后,Jest 将重新导入任何必需的模块。想象一下,无需处理其他测试中的所有模拟模块,就可以从头开始。
jest.resetModuleRegistry只是resetModules的别名,见:
https://github.com/facebook/jest/blob/7f69176c/packages/jest-runtime/src/index.ts#L1147
了解清除、重置和恢复在操作上有何不同:
https://repl.it/@sepehr/jest-mock-api-reset-restore#jest-mock-apis.test.js
describe('jest mock reset/restore api', () => {
describe('when calling mockReset() on a test double with custom impl.', () => {
describe('if the test double is a spy', () => {
test('jest replaces the impl. to a new undefined-returning jest.fn()', () => {
const module = { api: () => 'actual' }
jest.spyOn(module, 'api').mockImplementation(() => 'spy mocked')
expect(module.api()).toStrictEqual('spy mocked')
expect(module.api).toHaveBeenCalledTimes(1)
module.api.mockReset()
expect(module.api()).toStrictEqual(undefined)
expect(module.api).toHaveBeenCalledTimes(1)
})
})
describe('if the test double is "not" a spy', () => {
test('jest replaces the impl. to a new undefined-returning jest.fn()', () => {
const api = jest.fn(() => 'non-spy mocked')
expect(api()).toStrictEqual('non-spy mocked')
expect(api).toHaveBeenCalledTimes(1)
api.mockReset()
expect(api()).toStrictEqual(undefined)
expect(api).toHaveBeenCalledTimes(1)
})
})
})
describe('when calling mockRestore() on a test double with custom impl.', () => {
describe('if the test double is "not" a spy', () => {
test('jest resets the impl. to a new undefined-returning jest.fn()', () => {
const api = jest.fn(() => 'non-spy mocked')
expect(api()).toStrictEqual('non-spy mocked')
expect(api).toHaveBeenCalledTimes(1)
api.mockRestore()
expect(api()).toStrictEqual(undefined)
expect(api).toHaveBeenCalledTimes(1)
})
})
describe('if the test double is a spy', () => {
test('jest restores the original impl. of that spy', () => {
const module = { api: () => 'actual' }
jest.spyOn(module, 'api').mockImplementation(() => 'spy mocked')
expect(module.api()).toStrictEqual('spy mocked')
expect(module.api).toHaveBeenCalledTimes(1)
module.api.mockRestore()
expect(module.api()).toStrictEqual('actual')
expect(module.api).not.toHaveProperty('mock')
})
})
})
})
PASS ./jest-mock-apis.test.js
jest mock reset/restore api
when calling mockReset() on a test double with custom impl.
if the test double is a spy
✓ jest replaces the impl. to a new undefined-returning jest.fn() (18ms)
if the test double is "not" a spy
✓ jest replaces the impl. to a new undefined-returning jest.fn() (17ms)
when calling mockRestore() on a test double with custom impl.
if the test double is "not" a spy
✓ jest resets the impl. to a new undefined-returning jest.fn() (2ms)
if the test double is a spy
✓ jest restores the original impl. of that spy (7ms)
【讨论】:
感谢@sepehr 的回答。
我认为通过示例更容易理解。
快速提示:
clear
reset
restore。import {Calculator} from './calculator';
describe('calculator add', function () {
let calculator = new Calculator();
const mockAdd = jest.spyOn(calculator, 'add');
it('mock the add method', function () {
calculator.add = mockAdd.mockReturnValue(5);
expect(calculator.add(1, 2)).toBe(5);
});
it('because we didnt clear mock, the call times is 2', function () {
expect(calculator.add(1, 2)).toBe(5);
expect(mockAdd).toHaveBeenCalledTimes(2);
});
it('After clear, now call times should be 1', function () {
jest.clearAllMocks();
expect(calculator.add(1, 2)).toBe(5);
expect(mockAdd).toHaveBeenCalledTimes(1);
});
it('we reset mock, it means the mock has no return. The value would be undefined', function () {
jest.resetAllMocks();
expect(calculator.add(1, 2)).toBe(undefined);
});
it('we restore the mock to original method, so it should work as normal add.', function () {
jest.restoreAllMocks();
expect(calculator.add(1, 2)).toBe(3);
});
});
【讨论】: