在Jest/NestJS中如何mock snowflake-sdk等第三方模块?
问题诊断
你的测试代码存在4个核心错误,共同导致了超时问题:
- execute方法入参不匹配:原业务代码中
connection.execute接收的是包含sqlText和complete回调字段的对象,你mock的方法写了3个独立参数,完全匹配不上调用逻辑 - 没有触发complete回调:
export方法返回的Promise完全依赖complete回调触发resolve/reject,你mock的execute只打了日志,根本没调用传入的complete函数,Promise永远处于pending状态,自然会超时 - 缺少destroy方法实现:原业务代码finally块会调用
connection.destroy,你mock的connection对象没有这个方法,执行到这一步会抛出未定义错误 - expect语法错误:你已经对
snowflakeClient.export加了await,拿到的是普通值而非Promise,再调用.resolves会直接报错
修复后的测试代码
import { SnowflakeClient } from 'src/snowflake/snowflake-client'; import { Test } from '@nestjs/testing'; describe('SnowflakeClient', () => { let snowflakeClient: SnowflakeClient; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [SnowflakeClient], }).compile(); snowflakeClient = moduleRef.get<SnowflakeClient>(SnowflakeClient); }); describe('export', () => { it('should export a SQL query', async () => { // 构造正确的connection mock const connectionMock = { execute: jest.fn((options) => { // 直接调用complete回调,模拟无错误执行场景 options.complete(null); }), destroy: jest.fn((callback) => { // mock destroy方法无错误 callback(null); }) }; // mock getConnection直接返回上面的mock对象 jest.spyOn(snowflakeClient, 'getConnection').mockReturnValue(connectionMock); const bucket = 's3://bucketName'; const filename = '/reports/test.csv'; const sql = 'select * from customers limit 100'; // 正确的校验写法,直接验证返回结果 expect(await snowflakeClient.export(bucket, filename, sql)).toBe(true); // 可选:增加调用校验,验证参数是否符合预期 expect(connectionMock.execute).toHaveBeenCalledWith(expect.objectContaining({ sqlText: `COPY INTO 's3://bucketName/reports/test.csv' FROM (select * from customers limit 100)` })); expect(connectionMock.destroy).toHaveBeenCalled(); }); }); });
如果需要测试执行报错的场景,只要在mock execute的时候给complete传错误对象即可:
connectionMock.execute.mockImplementation((options) => { options.complete(new Error('snowflake execute error')); });
然后校验Promise是否抛出对应错误即可。
内容的提问来源于stack exchange,提问作者Marcelo Juventino
相关产品推荐
相关产品推荐

