Jest Mock导入模块异步函数报类型不匹配错误解决方案
报错原因
snowflake-promise@4.x版本中,execute是Snowflake类的实例方法,挂载在Snowflake.prototype或者类的实例对象上,不属于类的静态属性。- 原代码直接调用
jest.spyOn(Snowflake, 'execute'),是尝试在类本身的静态属性上查找execute方法,TypeScript类型检查时发现Snowflake类的静态属性集合中不存在名为execute的键,因此推导第二个参数的合法值类型为never,抛出Argument of type '"execute"' is not assignable to parameter of type 'never'的类型错误。 jest.mock('snowflake-promise')虽然会自动mock整个模块,但不会自动修正方法挂载位置查找错误的问题。
正确Mock异步实例方法的方案
方案1:全局监听所有实例的execute方法(推荐)
直接在类的原型上打spy,所有通过new Snowflake()创建的实例调用execute时都会被拦截:
jest.mock('snowflake-promise'); import { Snowflake } from 'snowflake-promise'; // 将mock后的类转为Jest认可的mock类类型,简化后续类型提示 const MockedSnowflake = Snowflake as jest.MockedClass<typeof Snowflake>; describe('Snowflake相关逻辑测试', () => { beforeEach(() => { // 每个用例执行前清空mock记录,避免用例间状态污染 MockedSnowflake.mockClear(); // 在原型上给execute方法打spy,设置异步mock返回值 jest.spyOn(MockedSnowflake.prototype, 'execute').mockResolvedValue(undefined); }); test('业务逻辑会正确调用execute方法', async () => { // 此处执行你的业务逻辑,比如内部会初始化Snowflake实例并调用execute的函数 // await runYourBusinessCode(); // 断言校验 expect(MockedSnowflake.prototype.execute).toHaveBeenCalled(); // 如果需要校验具体实例的调用参数,可以通过mock.instances拿到对应实例 // const testInstance = MockedSnowflake.mock.instances[0]; // expect(testInstance.execute).toHaveBeenCalledWith('预期的SQL语句'); }); });
方案2:针对单个实例监听
如果你不需要全局拦截,只需要给特定实例的execute打spy,可以在实例创建后单独绑定spy:
test('单个实例的execute方法测试', async () => { // 创建实例,由于模块已经被mock,传入的配置不会真的发起连接 const snowflakeClient = new Snowflake({ account: 'test', username: 'test', password: 'test' }); // 直接在实例上打spy const executeSpy = jest.spyOn(snowflakeClient, 'execute').mockResolvedValue([{ queryResult: 1 }]); // 执行依赖该实例的业务逻辑 // await yourBusinessFunc(snowflakeClient); // 断言校验 expect(executeSpy).toHaveBeenCalledTimes(1); });
注意:所有类的非静态方法都不会直接挂载在类构造函数本身,监听实例方法时要么挂载到
prototype,要么挂载到具体实例对象上,否则就会触发类似的类型错误。
内容的提问来源于stack exchange,提问作者Hoppe
相关产品推荐
相关产品推荐

