Contents

本地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 数据库,它的性能并不能反映生产中的真实性能。