如何用Jest对类型安全的NestFactory.create方法进行部分Mock
问题
我有一个TypeScript应用,正在使用Jest来Mock NestFactory类的create方法。通常,create方法会返回包含20余个方法/属性的INestApplication实例,但我仅关注其中的listen方法。我希望Mock create方法使其返回带有Mock化listen的对象以开展测试,当前实现会触发类型错误,且不想通过转换为any类型破坏类型安全,请问如何实现类型安全的Mock?
代码示例:
import { NestFactory } from '@nestjs/core'; // Jest自动Mock jest.mock('@nestjs/core'); // 获取带类型安全的Mocked NestFactory const mockedNestFactory = jest.mocked(NestFactory); test('', () => { // 希望create返回的Mock化listen函数 const mockedListen = jest.fn(); // 此处触发类型错误,因返回对象仅含listen,缺少INestApplication的其他成员 mockedNestFactory.create.mockResolvedValue({ listen: mockedListen, }); });
解决方案
方案1:使用Partial类型结合安全断言
导入INestApplication后,用Partial<INestApplication>定义仅包含listen的mock对象,再通过类型断言转换为INestApplication。这种方式既保留类型检查,又无需实现所有未用到的属性。
import { NestFactory, INestApplication } from '@nestjs/core'; jest.mock('@nestjs/core'); const mockedNestFactory = jest.mocked(NestFactory); test('测试NestFactory创建应用并监听', async () => { const mockedListen = jest.fn().mockResolvedValue(true); // 定义仅包含listen的Partial对象 const mockApp: Partial<INestApplication> = { listen: mockedListen, }; // 安全断言为INestApplication(测试中不会访问其他属性) mockedNestFactory.create.mockResolvedValue(mockApp as INestApplication); // 执行测试逻辑 const app = await NestFactory.create(); await app.listen(3000); expect(mockedListen).toHaveBeenCalledWith(3000); });
方案2:用Pick提取所需类型
通过Pick<INestApplication, 'listen'>从原类型中仅提取listen方法的类型,确保mock对象的类型与原类型完全匹配,再进行断言。
import { NestFactory, INestApplication } from '@nestjs/core'; jest.mock('@nestjs/core'); const mockedNestFactory = jest.mocked(NestFactory); // 仅提取需要用到的listen方法类型 type MockedNestApp = Pick<INestApplication, 'listen'>; test('测试NestFactory的listen调用', async () => { const mockedListen = jest.fn().mockResolvedValue(true); const mockApp: MockedNestApp = { listen: mockedListen, }; mockedNestFactory.create.mockResolvedValue(mockApp as INestApplication); // 执行测试逻辑 await NestFactory.create().then(app => app.listen(3000)); expect(mockedListen).toHaveBeenCalled(); });
方案3:自定义mock实现并占位未用方法
如果需要访问多个方法但只关心listen,可以用mockImplementation返回一个包含listen和其他未用方法占位的对象,所有未用方法用jest.fn()填充即可。
import { NestFactory, INestApplication } from '@nestjs/core'; jest.mock('@nestjs/core'); const mockedNestFactory = jest.mocked(NestFactory); test('测试应用启动流程', async () => { const mockedListen = jest.fn().mockResolvedValue(true); mockedNestFactory.create.mockImplementation(async () => { return { listen: mockedListen, // 用jest.fn()占位未用到的必要方法 close: jest.fn(), init: jest.fn(), getHttpAdapter: jest.fn(), } as INestApplication; }); // 执行测试逻辑 const app = await NestFactory.create(); await app.listen(3000); expect(mockedListen).toHaveBeenCalledWith(3000); });
内容的提问来源于stack exchange,提问作者Mansur Ali Koroglu
相关产品推荐
相关产品推荐

