如何在Java版AWS Lambda中Mock DynamoDB?
问题原因
你的测试失败是因为Lambda代码中直接在handleRequest方法内创建了DynamoDbEnhancedClient实例(DynamoDbEnhancedClient.create()),Mockito无法拦截静态的create()调用,导致测试时实际发起了对真实DynamoDB服务的请求,从而触发了凭证过期的错误。
解决方案:依赖注入解耦
要正确Mock DynamoDB相关组件,必须将客户端的创建与Lambda业务逻辑解耦,通过构造函数注入的方式传入DynamoDbEnhancedClient,这样测试时可以替换为Mock实例。
步骤1:改造Lambda代码
修改FooLambda类,添加接收DynamoDbEnhancedClient的构造函数,同时保留无参构造(Lambda部署时需要无参构造初始化):
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.TableSchema; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; public class FooLambda implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { // 注入的DynamoDB增强客户端 private final DynamoDbEnhancedClient enhancedClient; // 无参构造,用于Lambda部署时初始化(自动创建客户端) public FooLambda() { this.enhancedClient = DynamoDbEnhancedClient.create(); } // 带参数的构造,用于测试时注入Mock客户端 public FooLambda(DynamoDbEnhancedClient enhancedClient) { this.enhancedClient = enhancedClient; } @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { try { DynamoDbTable<FooEntity> fooTable = enhancedClient.table("foo_table", TableSchema.fromBean(FooEntity.class)); Key fooKey = Key.builder() .partitionValue("foo_key") // 注意原代码拼写错误:foo_ket -> foo_key .build(); FooEntity fooItem = fooTable.getItem(GetItemEnhancedRequest.builder().key(fooKey).build()); String barValue = fooItem.getBar(); // 后续业务逻辑示例 APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); response.setStatusCode(200); response.setBody(barValue); return response; } catch (Exception e) { System.err.println(e.getMessage()); APIGatewayProxyResponseEvent errorResponse = new APIGatewayProxyResponseEvent(); errorResponse.setStatusCode(500); errorResponse.setBody("Error: " + e.getMessage()); return errorResponse; } } }
步骤2:编写正确的单元测试
现在可以通过构造函数注入Mock的DynamoDbEnhancedClient,完整Mock整个调用链:
import org.junit.Test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.TableSchema; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; public class FooLambdaTest { @Test public void testHandleRequest() { // 1. Mock各个组件 DynamoDbEnhancedClient mockEnhancedClient = mock(DynamoDbEnhancedClient.class); DynamoDbTable<FooEntity> mockFooTable = mock(DynamoDbTable.class); FooEntity mockFooEntity = mock(FooEntity.class); // 2. 配置Mock行为 when(mockEnhancedClient.table(eq("foo_table"), eq(TableSchema.fromBean(FooEntity.class)))) .thenReturn(mockFooTable); when(mockFooTable.getItem(any(GetItemEnhancedRequest.class))).thenReturn(mockFooEntity); when(mockFooEntity.getBar()).thenReturn("test_bar_value"); // 3. 创建Lambda实例并传入Mock客户端 FooLambda handler = new FooLambda(mockEnhancedClient); APIGatewayProxyRequestEvent input = new APIGatewayProxyRequestEvent(); // 4. 执行测试 APIGatewayProxyResponseEvent response = handler.handleRequest(input, null); // 5. 断言结果示例 assert response.getStatusCode() == 200; assert response.getBody().equals("test_bar_value"); } }
关键注意点
- 修正原代码中的拼写错误:
partitionValue("foo_ket")改为foo_key,避免实际运行时找不到数据。 - 必须保留Lambda的无参构造,否则AWS Lambda服务无法初始化你的函数。
- Mock时精确匹配参数(比如表名和Schema),能让测试逻辑更严谨。
内容的提问来源于stack exchange,提问作者Paul Chuang
相关产品推荐
相关产品推荐

