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