如何正确Mock AWS SDK的Cognito Identity Provider服务?
解决Jest Mock AWS CognitoIdentityServiceProvider验证失败问题
问题分析
你遇到的验证失败主要有三个原因:
- 名称拼写错误:Mock的是
CognitoIdentityServiceProvider,但验证时写的是CognitoIdentityProviderService(多了一个Service后缀),导致访问prototype.adminGetUser返回undefined。 - Mock对象结构错误:你当前的Mock是让构造函数返回实例方法,而非挂载到原型链上,所以直接访问
prototype上的方法会找不到。 - 实例引用不一致:测试文件中创建的
mockCognitoIdentityProviderService实例,和被测试模块内部初始化的实例不是同一个,导致spy无法捕获实际调用。
正确解决方案
方案一:预定义可追踪的Mock方法
将需要Mock的方法提前定义为独立的jest mock函数,确保所有实例共享同一个引用,直接验证这些预定义的mock即可。
// 预定义所有需要Mock的方法 const mockAdminGetUser = jest.fn().mockReturnThis(); const mockGetUser = jest.fn().mockReturnThis(); const mockAdminDeleteUser = jest.fn().mockReturnThis(); const mockAdminUpdateUserAttributes = jest.fn().mockReturnThis(); const mockAssociateSoftwareToken = jest.fn().mockReturnThis(); const mockAdminSetUserMFAPreference = jest.fn().mockReturnThis(); const mockVerifySoftwareToken = jest.fn().mockReturnThis(); const mockAdminCreateUser = jest.fn().mockReturnThis(); const mockAdminUserGlobalSignOut = jest.fn().mockReturnThis(); const mockPromise = jest.fn().mockResolvedValue(true); // Mock aws-sdk jest.mock('aws-sdk', () => ({ ...jest.requireActual('aws-sdk'), // 构造函数返回包含预定义mock方法的对象 CognitoIdentityServiceProvider: jest.fn(() => ({ adminGetUser: mockAdminGetUser, getUser: mockGetUser, adminDeleteUser: mockAdminDeleteUser, adminUpdateUserAttributes: mockAdminUpdateUserAttributes, associateSoftwareToken: mockAssociateSoftwareToken, adminSetUserMFAPreference: mockAdminSetUserMFAPreference, verifySoftwareToken: mockVerifySoftwareToken, adminCreateUser: mockAdminCreateUser, adminUserGlobalSignOut: mockAdminUserGlobalSignOut, promise: mockPromise, })), })); // 先导入AWS,再导入被测试模块 import AWS from 'aws-sdk'; import yourServiceModule from './your-service-module'; // 测试用例 test('adminGetUser方法被正确调用', async () => { // 调用被测试模块中的业务方法 await yourServiceModule.fetchUserInfo('user-pool-id', 'test-username'); // 直接验证预定义的mock函数 expect(mockAdminGetUser).toHaveBeenCalledWith({ UserPoolId: 'user-pool-id', Username: 'test-username' }); // 验证promise方法被调用 expect(mockPromise).toHaveBeenCalled(); });
方案二:捕获构造函数返回的实例Mock
如果被测试模块是在模块级别初始化Cognito实例(而非方法内部),可以通过构造函数的mock结果获取实例引用,进而验证方法调用。
jest.mock('aws-sdk', () => { // 定义实例Mock const cognitoMockInstance = { adminGetUser: jest.fn().mockReturnThis(), getUser: jest.fn().mockReturnThis(), adminDeleteUser: jest.fn().mockReturnThis(), adminUpdateUserAttributes: jest.fn().mockReturnThis(), associateSoftwareToken: jest.fn().mockReturnThis(), adminSetUserMFAPreference: jest.fn().mockReturnThis(), verifySoftwareToken: jest.fn().mockReturnThis(), adminCreateUser: jest.fn().mockReturnThis(), adminUserGlobalSignOut: jest.fn().mockReturnThis(), promise: jest.fn().mockResolvedValue(true), }; return { ...jest.requireActual('aws-sdk'), CognitoIdentityServiceProvider: jest.fn(() => cognitoMockInstance), }; }); import AWS from 'aws-sdk'; import yourServiceModule from './your-service-module'; test('验证adminGetUser调用', async () => { await yourServiceModule.someBusinessMethod(); // 获取构造函数返回的实例Mock const cognitoInstance = AWS.CognitoIdentityServiceProvider.mock.results[0].value; expect(cognitoInstance.adminGetUser).toHaveBeenCalledWith(/* 预期参数 */); });
关于aws-sdk-mock的正确用法
如果要使用aws-sdk-mock,需确保在导入被测试模块之前完成Mock配置,因为模块级别的实例会在导入时初始化:
import AWSMock from 'aws-sdk-mock'; import AWS from 'aws-sdk'; // 在导入被测试模块前Mock方法 AWSMock.mock('CognitoIdentityServiceProvider', 'adminGetUser', (params, callback) => { callback(null, { Username: 'test-user', UserAttributes: [] }); }); // 导入被测试模块 import yourServiceModule from './your-service-module'; test('验证adminGetUser参数', async () => { await yourServiceModule.fetchUserInfo('pool-id', 'test-user'); // 获取调用记录 const [callParams] = AWSMock.calls('CognitoIdentityServiceProvider', 'adminGetUser')[0]; expect(callParams).toEqual({ UserPoolId: 'pool-id', Username: 'test-user' }); });
内容的提问来源于stack exchange,提问作者VIVID
相关产品推荐
相关产品推荐

