如何在Jest中重置方法的mockImplementation并重新指定返回值
解决Jest中Mock方法在不同测试用例设置不同返回值的问题
问题场景
已为TestService实现Mock,第一个测试用例因checkIfExistsInDB返回false执行成功,但第二个测试用例需要将该Mock方法改为返回true,尝试两种方法均无效:
初始Mock代码
jest.mock('../../lib/testService', () => ({ TestService : jest.fn(() => ({ callAPIProd: jest.fn().mockImplementation(() => Promise.resolve([{ DateTime: '2022-01-01'}])), getAuthToken: jest.fn().mockImplementation(() => Promise.resolve({ data: 'mock token' })), checkIfExistsInDB: jest.fn().mockImplementation(() => Promise.resolve(false)), })), }));
测试用例代码
describe('getRates', () => { it('should insert rates into DB if not already available', async () => { const req = {} as Request; const res = { send: jest.fn() } as unknown as Response; await integration.getRates(req, res); expect(res.send).toHaveBeenCalledWith('New Rates Received'); }); it('should send response if rates are already available in DB', async () => { const req = {} as Request; const res = { send: jest.fn() } as unknown as Response; // 尝试过的两种无效方法 // #1 重新调用jest.mock,无效 // jest.mock(...) // #2 修改prototype,无效 // TestService.prototype.checkIfExistsInDB = jest.fn().mockResolvedValue(true) await integration.getRates(req, res); expect(res.send).toHaveBeenCalledWith('Rates already available in DB'); }); });
无效原因分析
- 测试用例内调用
jest.mock无效:jest.mock会被Jest自动提升到模块顶部执行,测试用例内部的jest.mock无法覆盖模块级的Mock配置。 - 修改
prototype无效:TestService是一个返回普通对象的工厂函数(jest.fn()),并非类,不存在prototype属性,修改它不会影响Mock实例的方法。
正确解决方案
步骤1:获取Mock实例的方法引用
在模块顶部导入TestService后,直接获取Mock工厂函数返回的实例引用:
import { TestService } from '../../lib/testService'; import integration from './your-integration-module'; // 替换为实际路径 import type { Request, Response } from 'express'; jest.mock('../../lib/testService', () => ({ TestService : jest.fn(() => ({ callAPIProd: jest.fn().mockResolvedValue([{ DateTime: '2022-01-01'}]), getAuthToken: jest.fn().mockResolvedValue({ data: 'mock token' }), checkIfExistsInDB: jest.fn().mockResolvedValue(false), })), })); // 获取TestService Mock返回的实例对象 const mockTestService = TestService.mock.results[0].value;
步骤2:在测试用例中重置并修改Mock返回值
在第二个测试用例中,直接重置目标Mock方法并设置新的返回值:
describe('getRates', () => { // 可选:每次测试前重置所有Mock,避免用例间污染 beforeEach(() => { jest.clearAllMocks(); // 重置为默认返回值 mockTestService.checkIfExistsInDB.mockResolvedValue(false); }); it('should insert rates into DB if not already available', async () => { const req = {} as Request; const res = { send: jest.fn() } as unknown as Response; await integration.getRates(req, res); expect(res.send).toHaveBeenCalledWith('New Rates Received'); }); it('should send response if rates are already available in DB', async () => { const req = {} as Request; const res = { send: jest.fn() } as unknown as Response; // 修改checkIfExistsInDB的返回值为true mockTestService.checkIfExistsInDB.mockResolvedValue(true); await integration.getRates(req, res); expect(res.send).toHaveBeenCalledWith('Rates already available in DB'); }); });
替代写法:使用mockReturnValueOnce
如果只需要当前测试用例临时改变返回值,也可以用mockReturnValueOnce:
mockTestService.checkIfExistsInDB.mockReturnValueOnce(Promise.resolve(true));
内容的提问来源于stack exchange,提问作者MUK
相关产品推荐
相关产品推荐

