1. 概要

AmazonのDynamoDBを使用するアプリケーションを開発する場合、ローカルインスタンスがなくても統合テストを開発するのは難しい場合があります。

このチュートリアルでは、統合テストのためにローカルDynamoDBを設定、開始、停止する複数の方法について説明します。

このチュートリアルは、既存のDynamoDBの記事も補完します。

2. 構成

2.1. Mavenのセットアップ

DynamoDB Local は、すべてのDynamoDBAPIをサポートするAmazonによって開発されたツールです。 本番環境で実際のDynamoDBテーブルを直接操作するのではなく、ローカルで実行します。

まず、DynamoDBローカル依存関係をMaven構成の依存関係のリストに追加します。

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>DynamoDBLocal</artifactId>
    <version>1.11.86</version>
    <scope>test</scope>
</dependency>

次に、依存関係がMaven Centralリポジトリに存在しないため、AmazonDynamoDBリポジトリも追加する必要があります。

現在のIPアドレスのジオロケーションに最も近いAmazonサーバーを選択できます。

<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 test-compile(mvn test-compile)を少なくとも1回実行する必要があります。

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();

    //...
}

 

まとめる前に、非常に簡単に説明します。DynamoDBLocalはSQLiteデータベースを内部で使用するため、そのパフォーマンスは本番環境での実際のパフォーマンスを反映していません。

5. 結論

この記事では、統合テストを実行するためにDynamoDBLocalをセットアップおよび設定する方法を見てきました。

いつものように、ソースコードと構成例はGithubにあります。