Test Local DynamoDB plus facile

j'utilise DynamoDB local pour les tests unitaires. Il n'est pas mauvais, mais il a quelques inconvénients. Plus précisément:

  • vous devez d'une façon ou d'une autre démarrer le serveur avant que vos tests ne s'exécutent
  • le serveur n'est pas démarré et arrêté avant chaque test donc les tests deviennent interdépendants sauf si vous ajoutez du code pour supprimer toutes les tables, etc. après chaque test
  • tous les développeurs doivent l'avoir installé

Ce que je veux faire, c'est quelque chose comme mettre la DynamoDB local jar, et les autres jars dont il dépend, dans mon répertoire test/resources (J'écris Java). Puis, avant chaque test, je le lançais, avec-inMemory, et après le test je l'arrêterais. De cette façon, quiconque tire sur le git repo obtient une copie de tout ce dont il a besoin pour exécuter les tests et chaque test est indépendant des autres.

j'ai trouvé un moyen de faire ce travail, mais il est laid, donc je cherche des alternatives. La solution est de mettre un .fichier zip de la DynamoDB Local stuff dans test / resources, puis dans une méthode @Before, Je l'extrai dans un répertoire temporaire et je démarre un nouveau processus java pour l'exécuter. Cela fonctionne, mais il est laid et a quelques inconvénients:

  • tout le monde a besoin de l'exécutable java sur leur $PATH
  • je dois déballer un zip sur le disque local. Utiliser un disque local est souvent difficile pour tester, surtout avec des compilations continues et autres.
  • j'ai lancer un processus et attendre pour commencer pour chaque test unitaire, puis tuer ce processus après chaque test. En plus d'être lent, le potentiel pour les processus de gauche-sur semble laid.

Il semble qu'il devrait y avoir un moyen plus facile. DynamoDB Local est, après tout, juste du code Java. Est-ce que je ne peux pas d'une façon ou d'une autre demander à la JVM de se bifurquer et de regarder à l'intérieur des ressources pour construire un chemin de classe? Ou, encore mieux, ne puis-je pas simplement appeler le main méthode de DynamoDb Local à partir d'un autre thread pour que tout se passe en un seul processus? Tout des idées?

PS: je suis au courant de L'Alternateur, mais il semble avoir d'autres inconvénients, donc je suis enclin à rester avec la solution supportée par Amazon si je peux le faire fonctionner.

31
demandé sur Oliver Dain 2014-11-13 07:57:04

8 réponses

pour utiliser DynamoDBLocal vous devez suivre ces étapes.

  1. Direct DynamoDBLocal Dépendance
  2. Obtenir Natif SQLite4Java dépendances
  3. Set sqlite4java.library.path pour afficher les bibliothèques natives

1. Obtenez La Dépendance Dynamodblocale Directe

C'est le plus facile. Vous avez besoin de ce dépôt comme expliqué dans forums AWS.

<!--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. Obtenir Natif Sqlite4java dependencies

Si vous n'ajoutez pas ces dépendances, vos tests échoue avec 500 erreur interne.

tout d'Abord, ajoutez ces dépendances:

<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>

puis, ajoutez ce plugin pour obtenir des dépendances natives à un dossier spécifique:

<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. Set sqlite4java.library.path pour afficher les bibliothèques natives

comme dernière étape, vous devez définir sqlite4java.library.path propriété du système dans le répertoire natif-libs. C'est OK pour le faire avant de créer votre serveur local.

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

après ces étapes, vous pouvez utiliser DynamoDBLocal comme bon vous semble. Voici une règle de Junit qui crée un serveur local pour cela.

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

Vous pouvez utiliser cette règle comme ceci

@RunWith(JUnit4.class)
public class UserDAOImplTest {

    @ClassRule
    public static final LocalDynamoDBCreationRule dynamoDB = new LocalDynamoDBCreationRule();
}
48
répondu bhdrkn 2017-10-26 12:54:06

vous pouvez utiliser DynamoDB Local comme une dépendance de test Maven dans votre code de test, comme indiqué dans ce annonce. Vous pouvez exécuter sur HTTP:

import com.amazonaws.services.dynamodbv2.local.main.ServerRunner;
import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer;

final String[] localArgs = { "-inMemory" };
DynamoDBProxyServer server = ServerRunner.createServerFromCommandLineArgs(localArgs);
server.start();
AmazonDynamoDB dynamodb = new AmazonDynamoDBClient();
dynamodb.setEndpoint("http://localhost:8000");
dynamodb.listTables();
server.stop();

vous pouvez également exécuter en mode embedded:

import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;

AmazonDynamoDB dynamodb = DynamoDBEmbedded.create();
dynamodb.listTables();
14
répondu Alexander Patrikalakis 2015-07-18 04:36:24

il s'agit d'une reformulation de la réponse de bhdrkn pour les utilisateurs de Gradle (la sienne est basée sur Maven). C'est toujours les mêmes trois étapes:

  1. Direct DynamoDBLocal Dépendance
  2. Obtenir Natif SQLite4Java dépendances
  3. Définir sqlite4java.bibliothèque.chemin de montrer bibliothèques natives

1. Obtenez La Dépendance Dynamodblocale Directe

ajouter à la section dépendances de votre build.gradle fichier...

dependencies {
    testCompile "com.amazonaws:DynamoDBLocal:1.+"
}

2. Obtenir Natif SQLite4Java dépendances

les bibliothèques sqlite4java seront déjà téléchargées en tant que dépendance de DynamoDBLocal, mais les fichiers de la bibliothèque doivent être copiés au bon endroit. Ajouter à votre construction.dossier gradle...

task copyNativeDeps(type: Copy) {
    from(configurations.compile + configurations.testCompile) {
        include '*.dll'
        include '*.dylib'
        include '*.so'
    }
    into 'build/libs'
}

3. Set sqlite4java.bibliothèque.chemin de montrer bibliothèques natives

nous devons dire à Gradle de courir copyNativeDeps pour tester et dire à sqlite4java où trouver les fichiers. Ajouter à votre construire.dossier gradle...

test {
    dependsOn copyNativeDeps
    systemProperty "java.library.path", 'build/libs'
}
10
répondu Jeffery Grajkowski 2018-09-12 15:00:26

j'ai enveloppé les réponses ci-dessus en deux JUnit rules cela ne nécessite pas de modifications au script de compilation car les règles traitent les éléments de bibliothèque natifs. J'ai fait cela car j'ai trouvé que L'idée n'aimait pas les solutions de Gradle/Maven comme il vient de se déclencher et a fait sa propre chose anyhoos.

cela signifie que les étapes sont:

  • Get the Assortimentofjunitrules version 1.5.32 or above dependency
  • Get the Direct DynamoDBLocal dépendance
  • ajouter le LocalDynamoDbRule ou HttpDynamoDbRule à votre test JUnit.

Maven:

<!--Dependency:-->
<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>DynamoDBLocal</artifactId>
        <version>1.11.0.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.github.mlk</groupId>
      <artifactId>assortmentofjunitrules</artifactId>
      <version>1.5.36</version>
      <scope>test</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>

Gradle:

repositories {
  mavenCentral()

   maven {
    url = "https://s3-us-west-2.amazonaws.com/dynamodb-local/release"
  }
}

dependencies {
    testCompile "com.github.mlk:assortmentofjunitrules:1.5.36"
    testCompile "com.amazonaws:DynamoDBLocal:1.+"
}

Code:

public class LocalDynamoDbRuleTest {
  @Rule
  public LocalDynamoDbRule ddb = new LocalDynamoDbRule();

  @Test
  public void test() {
    doDynamoStuff(ddb.getClient());
  }
}
6
répondu Michael Lloyd Lee mlk 2018-09-12 14:58:56

pour les tests unitaires au travail, J'utilise Mockito, puis je me moque de L'AmazonDynamoDBClient. ensuite simulé les retours à l'aide lorsque. comme suit:

when(mockAmazonDynamoDBClient.getItem(isA(GetItemRequest.class))).thenAnswer(new Answer<GetItemResult>() {
        @Override
        public GetItemResult answer(InvocationOnMock invocation) throws Throwable {
            GetItemResult result = new GetItemResult();
            result.setItem( testResultItem );
            return result;
        }
    });

pas sûr si c'est ce que vous cherchez, mais c'est comment nous le faisons.

1
répondu Steve Smith 2015-03-04 17:23:23

Il y a le couple de nœud.js wrappers pour DynamoDB Local. Ceux-ci permettent d'exécuter facilement des essais unitaires en combinaison avec des coureurs de tâches comme gulp ou grunt. Essayez dynamodb-localhost, dynamodb-local

1
répondu Ashan 2016-07-09 11:13:18

dans Hadoop nous utilisons aussi DynamoDBLocal pour tester et déboguer le travail. S'il vous plaît voir comment il est utilisé comme exemple à: https://github.com/apache/hadoop/blob/HADOOP-13345/hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/s3guard/TestDynamoDBMetadataStore.java#L113

1
répondu Mingliang Liu 2017-03-22 21:46:31

j'ai trouvé que l'amazone pensions qu'aucun fichier d'index, de sorte que ne semble pas fonctionner d'une manière qui vous permet de mettre en comme ceci:

maven {
   url = "https://s3-us-west-2.amazonaws.com/dynamodb-local/release"
}

la seule façon d'obtenir les dépendances à charger est de télécharger DynamoDbLocal comme un jar et de l'introduire dans mon script de construction comme ceci:

dependencies {
    ...
    runtime files('libs/DynamoDBLocal.jar')
    ...
}

bien sûr, cela signifie que toutes les dépendances de SQLite et de Jetty doivent être apportées à la main - je suis toujours en train d'essayer d'obtenir ce droit. Si quelqu'un connaît un fiable pensions pour DynamoDbLocal, j'aimerais vraiment savoir.

1
répondu Michael Coxon 2018-04-21 22:03:45