You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:47:05