Jest中调用mockRestore()后再用mockImplementation()是否合理?
Jest 跨测试用例控制 Mock 行为的问题解析
为什么非得用 beforeEach 而不能用 beforeAll?
beforeAll是所有测试执行前只运行一次,你第一次创建的console.errorspy 是全局唯一的。测试1里用mockImplementation把它改成空函数禁用日志,测试2调用mockRestore会把这个spy还原成原始的console.error,但这个spy对象还是同一个。到测试3的时候,这个spy已经是还原后的状态,自然会正常输出错误日志——这就是你看到测试3出日志的原因。- 到测试4的时候,你再给这个spy加
mockImplementation,但之前的mockRestore已经把这个spy和原始方法的绑定解除了,相当于你在修改一个已经“失效”的spy,当然不会生效。 - 而
beforeEach是每个测试执行前都重新运行一次,每次都会创建一个全新的console.errorspy。这样每个测试的spy都是独立的:- 测试1:新spy → 用
mockImplementation禁用,用完可以还原 - 测试2:新spy → 直接还原(或者啥都不做,默认就是原始行为)
- 测试3:新spy → 不修改,正常输出日志
- 测试4:新spy → 用
mockImplementation禁用,完全生效
- 测试1:新spy → 用
调用 mockRestore() 后再用 mockImplementation() 行不行?
分情况:
- 如果是同一个spy对象,调用
mockRestore后,这个spy会被还原成原始方法,并且不再绑定到目标函数上。这时候再调用mockImplementation根本没用,因为这个spy已经和console.error没关系了。 - 如果是重新创建的spy(比如
beforeEach每次新建),先restore再mockImplementation是可以的,但完全没必要——直接创建spy后就加mockImplementation就行,restore是用来还原成原始方法的,除非你有先恢复再重新mock的特殊场景,否则纯纯多此一举。
靠谱的实现示例
方法一:用beforeEach统一创建,afterEach统一清理
beforeEach(() => { // 每个测试前都新建一个console.error的spy jest.spyOn(console, 'error'); }); afterEach(() => { // 每个测试后都还原所有mock,避免影响下一个测试 jest.restoreAllMocks(); }); test('测试1:禁用console.error', () => { console.error.mockImplementation(() => {}); // 执行你的业务代码,此时console.error不会输出任何内容 }); test('测试2:保留默认行为', () => { // 啥都不用改,spy默认会调用原始的console.error,正常输出日志 // 执行你的业务代码 }); test('测试3:保留默认行为', () => { // 同上,正常输出日志 // 执行你的业务代码 }); test('测试4:禁用console.error', () => { console.error.mockImplementation(() => {}); // 执行你的业务代码,console.error被禁用 });
方法二:在需要mock的测试里单独创建spy
test('测试1:禁用console.error', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); // 执行业务代码 errorSpy.mockRestore(); // 测试完手动还原 }); test('测试2:保留默认行为', () => { // 不创建spy,直接执行代码,console.error正常输出 }); test('测试3:保留默认行为', () => { // 同上,正常输出 }); test('测试4:禁用console.error', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); // 执行业务代码 errorSpy.mockRestore(); });
内容的提问来源于stack exchange,提问作者Christophe Messaouik
相关产品推荐
相关产品推荐

