如何使用Jest测试独立TypeScript文件并断言notify方法被调用
Jest测试立即执行TypeScript脚本的方案
你要测试的代码是顶层立即执行的异步函数(IIFE),导入文件时会自动运行,所以要提前完成所有依赖mock,再导入测试文件,具体实现步骤如下:
1. 核心思路
- 提前mock所有外部依赖:
NotificationService、日志工具、process.exit,避免真实逻辑执行影响测试 - 所有mock操作必须放在导入测试文件之前,否则IIFE执行时mock还未生效
- 异步IIFE需要等待微任务队列清空后再执行断言
2. 完整测试代码示例
假设你的源文件名为notify-task.ts,测试文件notify-task.test.ts代码如下:
// -------------- 第一步:提前mock所有外部依赖(必须写在导入测试文件之前)-------------- // mock NotificationService,将notify方法替换为jest mock函数 const mockNotify = jest.fn(); jest.mock('./notification-service', () => ({ NotificationService: jest.fn().mockImplementation(() => ({ notify: mockNotify })) })); // mock日志工具,避免真实打印 const mockLoggerError = jest.fn(); jest.mock('./logger', () => ({ logger: { error: mockLoggerError } })); // mock process.exit,避免测试进程被强制退出 const mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never); // mock常量SERVICE_NAME jest.mock('./constants', () => ({ SERVICE_NAME: 'test-notify-service' })); // -------------- 第二步:导入测试文件(导入后IIFE会立即执行)-------------- import './notify-task'; // -------------- 第三步:编写测试用例 -------------- describe('独立通知任务脚本测试', () => { beforeEach(() => { // 每次测试前清空所有mock的调用记录 jest.clearAllMocks(); }); it('正常执行时会调用notify方法,传入参数为test', async () => { // 等待异步IIFE的所有微任务执行完成 await Promise.resolve(); // 断言NotificationService被正确实例化 expect(require('./notification-service').NotificationService).toHaveBeenCalledTimes(1); // 断言notify方法被调用,参数符合预期 expect(mockNotify).toHaveBeenCalledTimes(1); expect(mockNotify).toHaveBeenCalledWith('test'); // 正常场景不会触发错误日志和进程退出 expect(mockLoggerError).not.toHaveBeenCalled(); expect(mockProcessExit).not.toHaveBeenCalled(); }); it('执行异常时会打印错误日志并退出进程', async () => { // 重置模块缓存,方便重新导入文件触发IIFE执行 jest.resetModules(); // 模拟notify方法抛出异常 const testError = new Error('通知发送失败'); mockNotify.mockRejectedValueOnce(testError); // 重新导入测试文件 import('./notify-task'); // 等待异步逻辑执行完成 await Promise.resolve(); // 断言错误日志和进程退出逻辑被正确触发 expect(mockLoggerError).toHaveBeenCalledTimes(1); expect(mockLoggerError).toHaveBeenCalledWith(testError, 'error while running test-notify-service'); expect(mockProcessExit).toHaveBeenCalledWith(1); }); });
3. 注意事项
- 如果你的依赖导入路径和示例不同,需要对应修改
jest.mock的第一个参数为实际导入路径 - 如果
notify是同步方法,也需要保留await Promise.resolve()的逻辑,确保IIFE执行完成后再做断言 - 多场景测试时必须调用
jest.resetModules()清空模块缓存,否则重复导入不会重新执行IIFE
内容的提问来源于stack exchange,提问作者dgzz
相关产品推荐
相关产品推荐

