本地DynamoDB实例集成测试
1. 概述
如果我们开发一个使用 Amazon 的DynamoDB 的应用程序,那么在没有本地实例的情况下开发集成测试可能会很棘手。
在本教程中,我们将探索为我们的集成测试配置、启动和停止本地 DynamoDB 的多种方法。
本教程还补充了我们现有的DynamoDB 文章 。
2. 配置
2.1. Maven 设置
DynamoDB Local 是由 Amazon 开发的工具,支持所有 DynamoDB API。它不直接在生产中操作实际的 DynamoDB 表,而是在本地执行它。 首先,我们将 DynamoDB Local 依赖项添加到 Maven 配置中的依赖项列表中:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>1.11.86</version>
<scope>test</scope>
</dependency>
接下来,我们还需要添加 Amazon DynamoDB 存储库,因为 Maven 中央存储库中不存在依赖项。
我们可以选择离我们当前 IP 地址地理位置最近的亚马逊服务器:
<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 系统属性中定义的特定文件夹中。 让我们将传递拉取的 SQLite4Java 库文件复制到名为native-libs的文件夹中:
<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 系统属性
现在,我们将使用名为sqlite4java.library.path的 JVM 系统属性引用先前创建的文件夹(SQLite4Java 库所在的位置) :
System.setProperty("sqlite4java.library.path", "native-libs");
为了以后成功运行测试,必须在sqlite4java.library.path系统属性定义的文件夹中包含所有 SQLite4Java 库。我们必须至少运行一次 Maven 测试编译 ( mvn test-compile )才能满足先决条件。
3. 设置测试数据库的生命周期
我们可以在使用*@BeforeClass注解的设置方法中定义代码来创建和启动本地DynamoDB服务器;并且,对称地,在使用@AfterClass*注解的拆卸方法中停止服务器。
在以下示例中,我们将在端口 8000 上启动本地 DynamoDB 服务器,并确保它在运行我们的测试后再次停止:
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在任何可用端口而不是固定端口上运行本地 DynamoDB 服务器。在这种情况下,我们还必须配置测试以将端点设置为正确的 DynamoDB 端口:
public String getAvailablePort() throws IOException {
ServerSocket serverSocket = new ServerSocket(0);
return String.valueOf(serverSocket.getLocalPort());
}
4. 替代方法:使用*@ClassRule*
我们可以将前面的逻辑包装在执行相同操作的 JUnit 规则中:
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*创建和注解一个实例,如下所示。同样,测试将在测试类初始化之前创建并启动本地 DynamoDB 服务器。
请注意,为了运行测试,测试规则的访问修饰符必须是public:
public class ProductInfoRepositoryIntegrationTest {
@ClassRule
public static LocalDbCreationRule dynamoDB = new LocalDbCreationRule();
//...
}
在结束之前,一个非常简短的说明——由于 DynamoDB Local 在内部使用 SQLite 数据库,它的性能并不能反映生产中的真实性能。