使用aws-sdk-client-mock模拟DynamoDB ScanCommand返回undefined排查
问题
在Node.js+Mocha-Sinon项目中实现了DynamoDB表扫描及批量删除功能:
- 在
repository.ts中定义scanData方法,通过DynamoDBDocumentClient发送ScanCommand; deleteData方法调用该方法获取数据后执行批量删除。
但单元测试时,用aws-sdk-client-mock的mockClient模拟ScanCommand始终返回undefined,尝试过stub相关函数也无法解决,请求排查建议。
相关代码
repository.ts 中的 scanData 方法
public async scanData( length: number, tableName: string, attributesToGet: string[], client: DynamoDBClient ): Promise<ScanCommandOutput> { const dynamoDBDDocClientOrigin = DynamoDBDocumentClient.from(client); const inputScan: ScanCommandInput = { TableName: tableName, Select: 'SPECIFIC_ATTRIBUTES', Limit: length, ProjectionExpression: `${attributesToGet[POSITION_TYP_DOC]},${attributesToGet[POSITION_NUM_DOC]}`, }; const scanCommand = new ScanCommand(inputScan); return dynamoDBDDocClientOrigin.send(scanCommand); }
deleteData 方法(调用扫描逻辑)
public async deleteData( tableName: string, attributesKeys: string[], client: DynamoDBClient ): Promise<IResponseDelete | IResponseErrorCopyOrDelete> { const repository = new DynamoDBRepositoryCollections(); const dynamoDBDDocClientOrigin = DynamoDBDocumentClient.from(client); const resultDescribeTable = await repository.getDescribeTable(tableName, client); if (resultDescribeTable.Table?.ItemCount) { const contador = resultDescribeTable.Table?.ItemCount; try { for (let i = contador; i > 0; i -= 25) { let dataToDelete = await repository.scanDataByLength( 25, tableName, attributesKeys, client ); const inputToDelete = await repository.batchDeleteInputObjectGenerator( dataToDelete, 25, tableName ); const command = new BatchWriteItemCommand(inputToDelete); if (dataToDelete.ScannedCount !== 0) { await dynamoDBDDocClientOrigin.send(command); } } return this.copyAndDeleteResponseMapper.mapResponseDelete(contador); } catch (e: any) { return this.mapper.mapError(e, 'Eliminado'); } } else { return this.mapper.mapError('Error por contador', 'Eliminado'); } }
测试代码
it('it should delete items when scanCommand is returning data in success way', async () => { const dynamodbClientDelete = new DynamoDBClient({}); const ddbMockDelete = mockClient(dynamodbClienteDelete); ddbMockDelete .on(DescribeTableCommand) .resolves(mockDescribeTable) .on(ScanCommand).resolves(dataScannedMock) // 此处返回undefined .on(BatchWriteItemCommand).resolves(mockBatchWrite); const result = await repository.deleteData( 'TableName', [attribute1, atributte2], dynamodbClientDelete ); expect(result.status).to.be.equal(200) });
排查建议
- 修正变量拼写错误:测试代码中创建
dynamodbClientDelete后,调用mockClient时传入的是dynamodbClienteDelete(多了一个字母'e'),导致mock的是未使用的客户端实例,实际业务代码用的客户端没有被mock,所以返回undefined。 - 核对方法名一致性:
deleteData中调用的是scanDataByLength,但定义的扫描方法是scanData,方法名不匹配会导致实际调用的方法未被mock,需统一方法名或调整测试中的mock目标。 - 适配DynamoDBDocumentClient的mock:
aws-sdk-client-mock默认mock基础DynamoDBClient,但业务代码是通过DynamoDBDocumentClient.from(client)创建文档客户端发送命令,需确保mock覆盖文档客户端的调用逻辑,或直接mockDynamoDBDocumentClient实例。 - 检查命令参数匹配:
aws-sdk-client-mock的on(ScanCommand)会严格匹配命令输入参数,需确认dataScannedMock对应的ScanCommand输入与scanData中构建的inputScan完全一致(包括TableName、Limit、ProjectionExpression等)。若需要宽松匹配,可使用on(ScanCommand, input => /* 自定义匹配逻辑 */)。 - 重构实例化逻辑:
deleteData内部新建new DynamoDBRepositoryCollections()实例,若该内部实例未使用传入的客户端,会导致mock失效。建议将repository实例作为依赖注入,而非在方法内部新建。
内容的提问来源于stack exchange,提问作者EddaK
相关产品推荐
相关产品推荐

