更轻松的 DynamoDB 本地测试

新手上路,请多包涵

我正在使用 本地 DynamoDB 进行单元测试。这还不错,但有一些缺点。具体来说:

  • 在测试运行之前,您必须以某种方式启动服务器
  • 服务器不会在每次测试之前启动和停止,因此测试变得相互依赖,除非您在每次测试后添加代码以删除所有表等
  • 所有开发人员都需要安装它

我想要做的是将 DynamoDB 本地 jar 和它所依赖的其他 jar 放在我的 test/resources 目录中(我正在用 Java 编写)。然后在每次测试之前我会启动它,运行 -inMemory ,在测试之后我会停止它。这样,任何拉下 git 存储库的人都可以获得运行测试所需的所有内容的副本,并且每个测试都独立于其他测试。

我找到了一种方法来完成这项工作,但它很丑陋,所以我正在寻找替代方案。我的解决方案是将 DynamoDB 本地内容的 .zip 文件放入 test/resources ,然后在 @Before 方法中,我将其解压缩到某个临时目录并开始一个新的java进程来执行它。这行得通,但它很丑陋并且有一些缺点:

  • 每个人都需要他们的 java 可执行文件 $PATH
  • 我必须将 zip 解压缩到本地磁盘。使用本地磁盘进行测试通常很冒险,尤其是在连续构建等情况下。
  • 我必须生成一个进程并等待它为每个单元测试启动,然后在每次测试后终止该进程。除了速度慢之外,遗留流程的可能性似乎也很难看。

似乎应该有一个更简单的方法。 DynamoDB Local 毕竟只是 Java 代码。我不能以某种方式要求 JVM 分叉自身并查看资源以构建类路径吗?或者,更好的是,我不能只从其他线程调用 DynamoDB Local 的 main 方法,这样这一切都发生在一个进程中吗?有任何想法吗?

PS:我知道 Alternator,但它似乎还有其他缺点,所以如果我能让它工作,我倾向于坚持使用 Amazon 支持的解决方案。

原文由 Oliver Dain 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 815
1 个回答

为了使用 DynamoDBLocal,您需要遵循以下步骤。

  1. 直接获取 DynamoDBLocal 依赖
  2. 获取本机 SQLite4Java 依赖项
  3. 设置 sqlite4java.library.path 以显示本机库

1.获取直接的DynamoDBLocal依赖

这是一个简单的。您需要此存储库,如此 所述。

 <!--Dependency:-->
<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>DynamoDBLocal</artifactId>
        <version>1.11.0.1</version>
        <scope></scope>
    </dependency>
</dependencies>
<!--Custom repository:-->
<repositories>
    <repository>
        <id>dynamodb-local</id>
        <name>DynamoDB Local Release Repository</name>
        <url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</url>
    </repository>
</repositories>

2.获取原生SQLite4Java依赖

如果您不添加这些依赖项,您的测试将失败并出现 500 内部错误。

首先,添加这些依赖项:

 <dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>sqlite4java</artifactId>
    <version>1.0.392</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>sqlite4java-win32-x86</artifactId>
    <version>1.0.392</version>
    <type>dll</type>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>sqlite4java-win32-x64</artifactId>
    <version>1.0.392</version>
    <type>dll</type>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>libsqlite4java-osx</artifactId>
    <version>1.0.392</version>
    <type>dylib</type>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>libsqlite4java-linux-i386</artifactId>
    <version>1.0.392</version>
    <type>so</type>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.almworks.sqlite4java</groupId>
    <artifactId>libsqlite4java-linux-amd64</artifactId>
    <version>1.0.392</version>
    <type>so</type>
    <scope>test</scope>
</dependency>

然后,添加此插件以获取对特定文件夹的本机依赖项:

 <build>
    <plugins>
        <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>
    </plugins>
</build>

3.设置 sqlite4java.library.path 显示原生库

作为最后一步,您需要将 sqlite4java.library.path 系统属性设置为 native-libs 目录。在创建本地服务器之前这样做是可以的。

 System.setProperty("sqlite4java.library.path", "native-libs");

完成这些步骤后,您可以根据需要使用 DynamoDBLocal。这是一个为此创建本地服务器的 Junit 规则。

 import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.local.main.ServerRunner;
import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer;
import org.junit.rules.ExternalResource;

import java.io.IOException;
import java.net.ServerSocket;

/**
 * Creates a local DynamoDB instance for testing.
 */
public class LocalDynamoDBCreationRule extends ExternalResource {

    private DynamoDBProxyServer server;
    private AmazonDynamoDB amazonDynamoDB;

    public LocalDynamoDBCreationRule() {
        // This one should be copied during test-compile time. If project's basedir does not contains a folder
        // named 'native-libs' please try '$ mvn clean install' from command line first
        System.setProperty("sqlite4java.library.path", "native-libs");
    }

    @Override
    protected void before() throws Throwable {

        try {
            final String port = getAvailablePort();
            this.server = ServerRunner.createServerFromCommandLineArgs(new String[]{"-inMemory", "-port", port});
            server.start();
            amazonDynamoDB = new AmazonDynamoDBClient(new BasicAWSCredentials("access", "secret"));
            amazonDynamoDB.setEndpoint("http://localhost:" + port);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void after() {

        if (server == null) {
            return;
        }

        try {
            server.stop();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public AmazonDynamoDB getAmazonDynamoDB() {
        return amazonDynamoDB;
    }

    private String getAvailablePort() {
        try (final ServerSocket serverSocket = new ServerSocket(0)) {
            return String.valueOf(serverSocket.getLocalPort());
        } catch (IOException e) {
            throw new RuntimeException("Available port was not found", e);
        }
    }
}

你可以像这样使用这个规则

@RunWith(JUnit4.class)
public class UserDAOImplTest {

    @ClassRule
    public static final LocalDynamoDBCreationRule dynamoDB = new LocalDynamoDBCreationRule();
}

原文由 bhdrkn 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题