Jest中spyOn的mockResolved异步测试失效问题解析
问题:Jest模拟API请求时部分mock失效的原因?
我使用Jest 24.8.0编写模拟API请求的测试用例,最初编写的代码如下:
class MyApi { public async getSomeData() { // request backend } } describe("Some test", () => { const apiSpy = jest.spyOn(MyApi, 'getSomeData'); afterEach(() => jest.restoreAllMocks()); test('some test 1', async () => { // arrange apiSpy.mockResolved(null); // act const result = await someFunctionCallingMyApi(); // assert }); test('some test 2', async () => { // arrange apiSpy.mockResolved(someMockObject); // act const result = await someFunctionCallingMyApi(); // assert }); // ...and more });
运行后发现部分mockResolved被忽略,函数实际调用了真实API而非模拟实现。
之后我将代码修改为:
describe("Some test", () => { let apiSpy: jest.SpyInstance; beforeEach(() => { apiSpy = jest.spyOn(MyApi, 'getSomeData'); }); afterEach(() => jest.restoreAllMocks()); test('some test 1', async () => { // arrange apiSpy.mockResolved(null); // act const result = await someFunctionCallingMyApi(); // assert }); test('some test 2', async () => { // arrange apiSpy.mockResolved(someMockObject); // act const result = await someFunctionCallingMyApi(); // assert }); // ...and more });
测试恢复正常,能够正确调用模拟函数。
原因分析
第一种写法失效的核心是spy实例的生命周期与Jest测试流程不匹配:
- 在第一个写法中,
apiSpy是在describe块作用域内声明的,仅会在所有测试用例执行前创建一次。 afterEach中的jest.restoreAllMocks()会把被spy替换的原始方法恢复。第一个测试用例执行完毕后,MyApi.getSomeData已经变回真实方法,但apiSpy还是指向最初创建的那个spy实例——这个实例已经不再关联到目标方法了。- 后续测试用例调用
apiSpy.mockResolved(...)时,修改的是已经失效的spy,自然无法覆盖真实方法,导致代码执行了真实API请求。
而修改后的写法解决了这个问题:
- 每个测试用例执行前,
beforeEach都会重新创建一个新的spy并替换MyApi.getSomeData,确保每次测试拿到的都是有效的、关联目标方法的spy实例。 - 测试结束后
afterEach恢复原始方法,下一个测试用例执行前又重新生成spy,实现了测试用例之间的完全隔离。
内容的提问来源于stack exchange,提问作者lsb
相关产品推荐
相关产品推荐

