Jest中函数已标记为Mock但仍执行原函数的问题排查
你遇到的问题核心在于同一个模块内的函数直接引用,不会被Jest对模块导出的Mock所覆盖。
你的getTables和getExportFiles在同一个模块中,getTables内部是直接调用模块作用域里的getExportFiles函数,而非通过模块的导出对象(比如rdsFormatter.getExportFiles)调用。当你用jest.mock替换模块导出的getExportFiles时,测试文件中导入的getExportFiles确实是Mock函数(所以jest.isMockFunction返回true),但模块内部getTables调用的还是原函数的引用,自然会触发原函数里的s3Client相关错误。
有两种常见的修复方式,根据你的代码结构选择:
方式一:修改模块内部调用方式,使用模块导出对象调用
调整getTables的代码,让它通过模块的导出对象来调用getExportFiles,这样Jest的Mock就能覆盖这个调用:
// rds-formatter.ts import * as self from './rds-formatter'; // 导入自身模块 export async function *getTables(assetId: string, payload: Record<string, unknown>) { // 通过self调用导出的getExportFiles const { parquetFiles, tablesInfoFile } = await self.getExportFiles(s3Client, payload); return parquetFiles; }
你的现有Mock代码不需要修改,此时getTables会使用Mock后的getExportFiles。
方式二:拆分函数到独立模块
将getExportFiles单独抽离到一个子模块(比如rds-export-files.ts),然后在rds-formatter.ts中导入使用:
// rds-export-files.ts export async function getExportFiles(s3Client, payload) { // 原函数逻辑 } // rds-formatter.ts import { getExportFiles } from './rds-export-files'; export async function *getTables(assetId: string, payload: Record<string, unknown>) { const { parquetFiles, tablesInfoFile } = await getExportFiles(s3Client, payload); return parquetFiles; }
然后在测试中Mock这个子模块:
import { getTables } from 'rds-formatter'; import { getExportFiles } from './rds-export-files'; jest.mock('./rds-export-files', () => ({ getExportFiles: jest.fn(() => Promise.resolve({ parquetFiles: '', tablesInfoFile: '' })) }));
这样getTables调用的就是Mock后的getExportFiles,不会触发原函数逻辑。
额外注意点
你的Mock返回值需要和getTables的解构匹配:原getExportFiles返回的是包含parquetFiles和tablesInfoFile的对象,但你当前的Mock返回的是字符串'return something',即使Mock生效,也会导致解构错误。记得把Mock返回值改成符合结构的对象,比如:
getExportFiles: jest.fn(() => Promise.resolve({ parquetFiles: '你期望的返回值', tablesInfoFile: '任意值' }))
内容的提问来源于stack exchange,提问作者NadavT

