1. 概述
当开发使用 Amazon DynamoDB 的应用时,没有本地实例进行集成测试会是个麻烦事。本文将探讨多种配置、启动和停止本地DynamoDB用于集成测试的方法。
本文是对现有 DynamoDB 文章 的补充。
2. 配置
2.1 Maven 设置
DynamoDB Local 是亚马逊开发的工具,支持所有 DynamoDB API。它不会直接操作生产环境的 DynamoDB 表,而是在本地执行。
首先,在 Maven 配置中添加 DynamoDB Local 依赖:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>1.11.86</version>
<scope>test</scope>
</dependency>
接下来需要添加 Amazon DynamoDB 仓库,因为该依赖不在 Maven 中央仓库:
<repository>
<id>dynamodb-local</id>
<name>DynamoDB Local Release Repository</name>
<url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</url>
</repository>
2.2 添加 SQLite4Java 依赖
DynamoDB Local 内部使用 SQLite4Java 库,因此运行测试时需要包含该库文件。SQLite4Java 库文件依赖测试运行环境,但声明 DynamoDBLocal 依赖后 Maven 会自动拉取。
添加构建步骤将原生库复制到指定文件夹(后续通过 JVM 系统属性引用):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy</id>
<phase>test-compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>test</includeScope>
<includeTypes>so,dll,dylib</includeTypes>
<outputDirectory>${project.basedir}/native-libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
2.3 设置 SQLite4Java 系统属性
通过 JVM 系统属性 sqlite4java.library.path
引用 SQLite4Java 库所在文件夹:
System.setProperty("sqlite4java.library.path", "native-libs");
⚠️ 关键前提:必须确保 sqlite4java.library.path
指定的文件夹包含所有 SQLite4Java 库文件。至少执行一次 mvn test-compile
来满足此条件。
3. 管理测试数据库生命周期
在 @BeforeClass
注解的 setup 方法中创建并启动本地 DynamoDB 服务器,在 @AfterClass
注解的 teardown 方法中停止服务器:
public class ProductInfoDAOIntegrationTest {
private static DynamoDBProxyServer server;
@BeforeClass
public static void setupClass() throws Exception {
System.setProperty("sqlite4java.library.path", "native-libs");
String port = "8000";
server = ServerRunner.createServerFromCommandLineArgs(
new String[]{"-inMemory", "-port", port});
server.start();
//...
}
@AfterClass
public static void teardownClass() throws Exception {
server.stop();
}
//...
}
✅ 动态端口技巧:使用 java.net.ServerSocket
获取可用端口替代固定端口:
public String getAvailablePort() throws IOException {
ServerSocket serverSocket = new ServerSocket(0);
return String.valueOf(serverSocket.getLocalPort());
}
此时必须配置测试使用正确的 DynamoDB 接口。
4. 替代方案:使用 @ClassRule
将上述逻辑封装为 JUnit Rule:
public class LocalDbCreationRule extends ExternalResource {
private DynamoDBProxyServer server;
public LocalDbCreationRule() {
System.setProperty("sqlite4java.library.path", "native-libs");
}
@Override
protected void before() throws Exception {
String port = "8000";
server = ServerRunner.createServerFromCommandLineArgs(
new String[]{"-inMemory", "-port", port});
server.start();
}
@Override
protected void after() {
this.stopUnchecked(server);
}
protected void stopUnchecked(DynamoDBProxyServer dynamoDbServer) {
try {
dynamoDbServer.stop();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
使用 @ClassRule
注解规则实例(注意访问修饰符必须为 public
):
public class ProductInfoRepositoryIntegrationTest {
@ClassRule
public static LocalDbCreationRule dynamoDB = new LocalDbCreationRule();
//...
}
⚠️ 性能提醒:DynamoDB Local 内部使用 SQLite 数据库,其性能不反映生产环境真实表现。
5. 总结
本文介绍了配置和使用 DynamoDB Local 进行集成测试的多种方法。完整源码和配置示例可在 GitHub 获取。