Mock类方法后仍出现DynamoDB凭证错误,求排查方案
问题描述
我在测试HouseManager类的getHouseFullInfo方法时遇到了异常:该方法依赖DynamoDBClient和DynamoDBDocumentClient从DynamoDB获取数据,我已Mock相关依赖,但运行测试时仍抛出「无效或无凭证」错误——按Mock逻辑本不该触发这个问题。
其他文件中使用相同依赖实现的函数测试均正常,但针对HouseManager尝试多种Mock方式均失败。我的测试代码如下:
import * as AWSMock from 'aws-sdk-mock'; import * as AWS from 'aws-sdk'; import { HouseManager } from '../../lambda/house_manager'; import { Logger } from '@aws-lambda-powertools/logger'; import { QueryInput, DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; // Assuming AWSMock has a way to mock AWS SDK v3 or using jest for mocking jest.mock('@aws-sdk/client-dynamodb'); jest.mock('@aws-lambda-powertools/logger'); jest.mock('@aws-sdk/lib-dynamodb') const loggerMock = { info: jest.fn(), error: jest.fn() } as unknown as Logger; new Logger(); describe('HouseManager', () => { let houseManager: HouseManager; let ddb: DynamoDBDocumentClient; beforeAll(() => { const ddbClient = new DynamoDBClient({ region: 'us-east-1', // Choose an appropriate region credentials: { accessKeyId: 'testing', secretAccessKey: 'testing', sessionToken: 'testing' } }); ddb = DynamoDBDocumentClient.from(ddbClient, { // Automatically remove undefined values marshallOptions: { removeUndefinedValues: true }, }); // Set the AWS SDK instance for mocking AWSMock.setSDKInstance(AWS); // Set the AWS Mock Response const mockResponse = { Items: [{ PK: `HOUSE#aa231eb4-2927-46f4-a625-f6167ebc019c`, data: { id: 'aa231eb4-2927-46f4-a625-f6167ebc019c', name: "Jest Test House", description: "This an automated test house for JEST.", owner: "JEST-0001", priceDetails: { dailyPriceAvg: 300, guestFee: 50, petFee: 20, priceCalendar: "c_f5f4ec60eb80b6b4c4824eeaa569da58f99eaa103cc0b0555ade5ae7fd746a0d@group.calendar.google.com" }, location: { active: true, cityId: "BSB", cityName: "Brasília", countryId: "BR", countryName: "Brasil", stateId: "DF", stateName: "Distrito Federal" }, active: true }, entity: 'HOUSE' }] }; AWSMock.mock('DynamoDB.DocumentClient', 'query', (params: QueryInput, callback: any) => { callback(null, mockResponse); }); }); afterAll(() => { AWSMock.restore(); }); beforeEach(() => { houseManager = new HouseManager(); jest.clearAllMocks(); }); describe('getHouseFullInfo', () => { it('should call the logger info method', () => { loggerMock.info('test'); expect(loggerMock.info).toHaveBeenCalledWith('test'); }); it('successfully retrieves house full information', async () => { const houseId = 'aa231eb4-2927-46f4-a625-f6167ebc019c'; const result = await houseManager.getHouseFullInfo(houseId); expect(result).toBeDefined(); expect(result.id).toEqual(houseId); expect(result.location.cityName).toEqual('Brasília'); expect(result.description).toEqual("This an automated test house for JEST."); expect(loggerMock.info).toHaveBeenCalled(); }, 10000); // Timeout set to 10 seconds; }); });
问题根源
你混用了AWS SDK v2的aws-sdk-mock工具和AWS SDK v3的客户端,aws-sdk-mock仅支持AWS SDK v2,而你代码中使用的@aws-sdk/client-dynamodb、@aws-sdk/lib-dynamodb是v3版本,导致Mock完全未生效,实际的DynamoDB客户端被初始化,触发了凭证校验错误。
解决方案
直接用Jest Mock AWS SDK v3的API,替换掉无效的aws-sdk-mock,同时修正Logger的Mock逻辑,确保HouseManager使用Mock实例。
修复后的测试代码
import { HouseManager } from '../../lambda/house_manager'; import { Logger } from '@aws-lambda-powertools/logger'; import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { DynamoDBDocumentClient, QueryCommand } from '@aws-sdk/lib-dynamodb'; // Mock AWS SDK v3 DynamoDBClient jest.mock('@aws-sdk/client-dynamodb', () => ({ DynamoDBClient: jest.fn().mockImplementation(() => ({ send: jest.fn(), })), })); // Mock DynamoDBDocumentClient及query逻辑 jest.mock('@aws-sdk/lib-dynamodb', () => ({ DynamoDBDocumentClient: { from: jest.fn().mockReturnValue({ send: jest.fn().mockResolvedValue({ Items: [{ PK: `HOUSE#aa231eb4-2927-46f4-a625-f6167ebc019c`, data: { id: 'aa231eb4-2927-46f4-a625-f6167ebc019c', name: "Jest Test House", description: "This an automated test house for JEST.", owner: "JEST-0001", priceDetails: { dailyPriceAvg: 300, guestFee: 50, petFee: 20, priceCalendar: "c_f5f4ec60eb80b6b4c4824eeaa569da58f99eaa103cc0b0555ade5ae7fd746a0d@group.calendar.google.com" }, location: { active: true, cityId: "BSB", cityName: "Brasília", countryId: "BR", countryName: "Brasil", stateId: "DF", stateName: "Distrito Federal" }, active: true }, entity: 'HOUSE' }] }), }), }, QueryCommand: jest.fn(), })); // Mock Powertools Logger jest.mock('@aws-lambda-powertools/logger', () => ({ Logger: jest.fn().mockImplementation(() => ({ info: jest.fn(), error: jest.fn(), })), })); describe('HouseManager', () => { let houseManager: HouseManager; let mockLogger: jest.Mocked<Logger>; beforeEach(() => { jest.clearAllMocks(); houseManager = new HouseManager(); // 获取Mock的Logger实例 mockLogger = new Logger() as jest.Mocked<Logger>; }); describe('getHouseFullInfo', () => { it('should call the logger info method', () => { mockLogger.info('test'); expect(mockLogger.info).toHaveBeenCalledWith('test'); }); it('successfully retrieves house full information', async () => { const houseId = 'aa231eb4-2927-46f4-a625-f6167ebc019c'; const result = await houseManager.getHouseFullInfo(houseId); expect(result).toBeDefined(); expect(result.id).toEqual(houseId); expect(result.location.cityName).toEqual('Brasília'); expect(result.description).toEqual("This an automated test house for JEST."); expect(mockLogger.info).toHaveBeenCalled(); // 验证QueryCommand是否被正确触发 expect(QueryCommand).toHaveBeenCalled(); }, 10000); }); });
关键说明
- AWS SDK v3采用命令式调用(如
QueryCommand),而非v2的documentClient.query回调模式,Mock需对应v3的API结构。 - 直接Mock
DynamoDBDocumentClient.from方法,让它返回预设了send方法的实例,send方法直接返回Mock数据的Promise。 - Logger的Mock通过替换整个模块实现,确保
HouseManager初始化时使用的是Mock实例,无需额外手动关联。
内容的提问来源于stack exchange,提问作者antonio Francisco de Arajo Net
相关产品推荐
相关产品推荐

