Tests locaux DynamoDB plus faciles

J’utilise DynamoDB local pour les tests unitaires. Ce n’est pas mal, mais a des inconvénients. Plus précisément:

  • Vous devez en quelque sorte démarrer le serveur avant que vos tests ne soient exécutés
  • Le serveur n’étant ni démarré ni arrêté avant chaque test, 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 le jar local de DynamoDB, et les autres jars dont il dépend, dans mon répertoire test / resources (j’écris Java). Ensuite, avant chaque test, je le -inMemory exécutant -inMemory et, après le test, je l’ -inMemory . De cette façon, quiconque arrête le repository git 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 cela, mais c’est moche, alors je cherche des alternatives. La solution est de mettre un fichier .zip contenant les éléments DynamoDB dans test / resources, puis dans une méthode @Before, de l’extraire dans un répertoire temporaire et de lancer un nouveau processus java pour l’exécuter. Cela fonctionne, mais c’est moche et a des inconvénients:

  • Tout le monde a besoin de l’exécutable Java sur son $ PATH
  • Je dois décompresser un fichier zip sur le disque local. L’utilisation d’un disque local est souvent risquée pour les tests, en particulier avec les versions continues et autres.
  • Je dois créer un processus et attendre son lancement pour chaque test unitaire, puis le tuer après chaque test. En plus d’être lente, le potentiel de processus restants 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 en quelque sorte demander à la JVM de se décomposer et de regarder à l’intérieur des ressources pour créer un classpath? Ou, mieux encore, ne puis-je pas simplement appeler la méthode main de DynamoDb Local à partir d’un autre thread afin que tout se déroule en un seul processus? Des idées?

PS: Je connais Alternator, mais il semble présenter d’autres inconvénients, et je suis donc enclin à restr avec la solution prise en charge par Amazon si je parviens à le faire fonctionner.

Pour utiliser DynamoDBLocal, vous devez suivre ces étapes.

  1. Obtenir une dépendance directe DynamoDBLocal
  2. Obtenir les dépendances natives de SQLite4Java
  3. Définissez sqlite4java.library.path pour afficher les bibliothèques natives

1. Obtenir une dépendance directe DynamoDBLocal

Celui-ci est le plus facile. Vous avez besoin de ce référentiel, comme expliqué dans les forums AWS .

    com.amazonaws DynamoDBLocal 1.11.0.1       dynamodb-local DynamoDB Local Release Repository https://s3-us-west-2.amazonaws.com/dynamodb-local/release   

2. Obtenir les dépendances natives SQLite4Java

Si vous n’ajoutez pas ces dépendances, vos tests échoueront avec une erreur interne 500.

Tout d’abord, ajoutez ces dépendances:

  com.almworks.sqlite4java sqlite4java 1.0.392 test   com.almworks.sqlite4java sqlite4java-win32-x86 1.0.392 dll test   com.almworks.sqlite4java sqlite4java-win32-x64 1.0.392 dll test   com.almworks.sqlite4java libsqlite4java-osx 1.0.392 dylib test   com.almworks.sqlite4java libsqlite4java-linux-i386 1.0.392 so test   com.almworks.sqlite4java libsqlite4java-linux-amd64 1.0.392 so test  

Ajoutez ensuite ce plugin pour obtenir des dépendances natives dans un dossier spécifique:

    org.apache.maven.plugins maven-dependency-plugin 2.10   copy test-comstack  copy-dependencies   test so,dll,dylib ${project.basedir}/native-libs       

3. Définissez sqlite4java.library.path pour afficher les bibliothèques natives

Enfin, vous devez définir la propriété système sqlite4java.library.path dans le répertoire native-libs. Vous pouvez le faire juste avant de créer votre serveur local.

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

Après ces étapes, vous pouvez utiliser DynamoDBLocal à votre guise. Voici une règle 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-comstack 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 Ssortingng port = getAvailablePort(); this.server = ServerRunner.createServerFromCommandLineArgs(new Ssortingng[]{"-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 Ssortingng getAvailablePort() { try (final ServerSocket serverSocket = new ServerSocket(0)) { return Ssortingng.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(); } 

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

 import com.amazonaws.services.dynamodbv2.local.main.ServerRunner; import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer; final Ssortingng[] 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 intégré:

 import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded; AmazonDynamoDB dynamodb = DynamoDBEmbedded.create(); dynamodb.listTables(); 

Ceci est un rappel de la réponse de bhdrkn pour les utilisateurs de Gradle (le sien est basé sur Maven). C’est toujours les trois mêmes étapes:

  1. Obtenir une dépendance directe DynamoDBLocal
  2. Obtenir des dépendances natives SQLite4Java
  3. Définissez sqlite4java.library.path pour afficher les bibliothèques natives

1. Obtenir une dépendance directe DynamoDBLocal

Ajoutez à la section des dépendances de votre fichier build.gradle …

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

2. Obtenir les dépendances natives SQLite4Java

Les bibliothèques sqlite4java seront déjà téléchargées en tant que dépendance de DynamoDBLocal, mais les fichiers de bibliothèque doivent être copiés au bon endroit. Ajoutez à votre fichier build.gradle …

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

3. Définissez sqlite4java.library.path pour afficher les bibliothèques natives

Nous devons dire à Gradle de lancer copyNativeDeps pour le test et à sqlite4java où trouver les fichiers. Ajoutez à votre fichier build.gradle …

 test { dependsOn copyNativeDeps systemProperty "java.library.path", 'build/libs' } 

J’ai résumé les réponses ci-dessus dans deux règles JUnit qui ne requièrent aucune modification du script de construction car les règles gèrent les éléments de la bibliothèque native. C’est ce que j’ai fait, car j’ai constaté qu’Idea n’aimait pas les solutions Gradle / Maven.

Cela signifie que les étapes sont les suivantes:

  • Récupère la dépendance AssortmentOfJUnitRules version 1.5.32 ou supérieure
  • Obtenez la dépendance Direct DynamoDBLocal
  • Ajoutez le LocalDynamoDbRule ou HttpDynamoDbRule à votre test JUnit.

Maven:

    com.amazonaws DynamoDBLocal 1.11.0.1 test   com.github.mlk assortmentofjunitrules 1.5.36 test      dynamodb-local DynamoDB Local Release Repository https://s3-us-west-2.amazonaws.com/dynamodb-local/release   

Gradle:

 repositories { mavenCentral() maven { url = "https://s3-us-west-2.amazonaws.com/dynamodb-local/release" } } dependencies { testComstack "com.github.mlk:assortmentofjunitrules:1.5.36" testComstack "com.amazonaws:DynamoDBLocal:1.+" } 

Code:

 public class LocalDynamoDbRuleTest { @Rule public LocalDynamoDbRule ddb = new LocalDynamoDbRule(); @Test public void test() { doDynamoStuff(ddb.getClient()); } } 

Pour les tests unitaires au travail, j’utilise Mockito, puis il suffit de simuler AmazonDynamoDBClient. puis simuler les retours en utilisant quand. comme suit:

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

Je ne sais pas si c’est ce que vous recherchez mais c’est comme ça que nous le faisons.

Il existe deux wrappers node.js pour DynamoDB Local. Celles-ci permettent d’exécuter facilement des tests unitaires en combinant des tâches comme gulp ou grunt. Essayez dynamodb-localhost , dynamodb-local

Dans Hadoop, nous utilisons également DynamoDBLocal pour les tests et le débogage. S’il vous plaît voir comment il est utilisé là 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

J’ai trouvé que le repo d’Amazon n’avait pas d’index, donc il ne semble pas fonctionner d’une manière qui vous permette de l’introduire comme ceci:

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

Le seul moyen de charger les dépendances est de télécharger DynamoDbLocal en tant que fichier jar et de l’insérer dans mon script de construction, comme suit:

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

Bien sûr, cela signifie que toutes les dépendances SQLite et Jetty doivent être apscopes manuellement – j’essaie toujours de le faire correctement. Si quelqu’un connaît un repo fiable pour DynamoDbLocal, j’aimerais vraiment savoir.