java - tables - Pruebas locales de DynamoDB más fáciles
dynamodb operations (8)
En Hadoop también usamos DynamoDBLocal para probar y depurar el trabajo. Vea cómo se usa allí como ejemplo en: https://github.com/apache/hadoop/blob/HADOOP-13345/hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/s3guard/TestDynamoDBMetadataStore.java#L113
Estoy usando DynamoDB local para pruebas unitarias. No está mal, pero tiene algunos inconvenientes. Específicamente:
- Tienes que iniciar el servidor de alguna manera antes de que se ejecuten tus pruebas
- El servidor no se inicia ni se detiene antes de cada prueba, por lo que las pruebas se vuelven interdependientes a menos que agregue código para eliminar todas las tablas, etc. después de cada prueba.
- Todos los desarrolladores deben tenerlo instalado
Lo que quiero hacer es algo así como poner el jar local de DynamoDB y los otros jarros de los que depende, en mi directorio de prueba / recursos (estoy escribiendo Java). Luego, antes de cada prueba, lo -inMemory
en marcha, funcionaba con -inMemory
, y después de la prueba lo detenía. De esa manera, cualquiera que esté bajando el repositorio de git obtiene una copia de todo lo que necesita para ejecutar las pruebas y cada prueba es independiente de las demás.
He encontrado una manera de hacer que esto funcione, pero es feo, así que estoy buscando alternativas. La solución que tengo es poner un archivo .zip de las cosas locales de DynamoDB en prueba / recursos, luego en un método @Before, lo extraigo a algún directorio temporal y comienzo un nuevo proceso java para ejecutarlo. Eso funciona, pero es feo y tiene algunos inconvenientes:
- Todo el mundo necesita el ejecutable de Java en su $ PATH
- Tengo que descomprimir un archivo zip en el disco local. Usar el disco local a menudo es arriesgado para probar, especialmente con versiones continuas y cosas por el estilo.
- Tengo que generar un proceso y esperar a que comience para cada prueba de unidad, y luego matar ese proceso después de cada prueba. Además de ser lento, el potencial de los procesos sobrantes parece feo.
Parece que debería haber una manera más fácil. DynamoDB Local es, después de todo, solo código Java. ¿No puedo de alguna manera pedirle a la JVM que se bifurque y mire dentro de los recursos para construir un classpath? O, mejor aún, ¿no puedo simplemente llamar al método main
de DynamoDb Local desde algún otro hilo para que todo esto ocurra en un solo proceso? ¿Algunas ideas?
PD: Estoy al tanto de Alternador, pero parece tener otros inconvenientes, por lo que me inclino a seguir con la solución compatible de Amazon si puedo hacerlo funcionar.
Esta es una reformulación de la respuesta de bhdrkn para los usuarios de Gradle (la suya está basada en Maven). Sigue siendo los mismos tres pasos:
- Obtener Directo DynamoDBLocal Dependencia
- Obtener las dependencias nativas de SQLite4Java
- Establezca sqlite4java.library.path para mostrar las bibliotecas nativas
1. Obtenga Dependencia Direct DynamoDBLocal
Agregue a la sección de dependencias de su archivo build.gradle ...
dependencies {
testCompile "com.amazonaws:DynamoDBLocal:1.+"
}
2. Obtener las dependencias nativas de SQLite4Java
Las bibliotecas sqlite4java ya se descargarán como una dependencia de DynamoDBLocal, pero los archivos de la biblioteca deben copiarse en el lugar correcto. Añádelo a tu archivo build.gradle ...
task copyNativeDeps(type: Copy) {
from(configurations.compile + configurations.testCompile) {
include ''*.dll''
include ''*.dylib''
include ''*.so''
}
into ''build/libs''
}
3. Establezca sqlite4java.library.path para mostrar las bibliotecas nativas
Necesitamos decirle a Gradle que ejecute copyNativeDeps
para probar y decirle a sqlite4java dónde encontrar los archivos. Añádelo a tu archivo build.gradle ...
test {
dependsOn copyNativeDeps
systemProperty "java.library.path", ''build/libs''
}
Hay un par de envoltorios node.js para DynamoDB Local. Esto permite ejecutar fácilmente pruebas unitarias combinadas con corredores de tareas como trago o gruñido. Pruebe con dynamodb-localhost , dynamodb-local
He encontrado que el repositorio de Amazon no tiene ningún archivo de índice, por lo que no parece funcionar de una manera que te permita incluirlo así:
maven {
url = "https://s3-us-west-2.amazonaws.com/dynamodb-local/release"
}
La única manera de conseguir que se carguen las dependencias es mediante la descarga de DynamoDbLocal como un archivo jar y llevarlo a mi script de compilación de esta manera:
dependencies {
...
runtime files(''libs/DynamoDBLocal.jar'')
...
}
Por supuesto, esto significa que todas las dependencias de SQLite y Jetty deben ser traídas a mano, todavía estoy tratando de hacer esto bien. Si alguien sabe de un repositorio confiable para DynamoDbLocal, me encantaría saberlo.
He incluido las respuestas anteriores en dos reglas JUnit que no requieren cambios en el script de compilación, ya que las reglas manejan las cosas de la biblioteca nativa. Hice esto porque me di cuenta de que a Idea no le gustaban las soluciones de Gradle / Maven, ya que simplemente funcionaba y hacía lo suyo en cualquier momento.
Esto significa que los pasos son:
- Obtenga la dependencia de AssortmentOfJUnitRules versión 1.5.32 o superior
- Obtener la dependencia Direct DynamoDBLocal
- Agregue LocalDynamoDbRule o HttpDynamoDbRule a su prueba 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.+"
}
Código:
public class LocalDynamoDbRuleTest {
@Rule
public LocalDynamoDbRule ddb = new LocalDynamoDbRule();
@Test
public void test() {
doDynamoStuff(ddb.getClient());
}
}
Para las pruebas unitarias en el trabajo, utilizo Mockito y me burlo del AmazonDynamoDBClient. luego simula los retornos usando cuándo. como el siguiente
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;
}
});
No estoy seguro de si eso es lo que buscas, pero así es como lo hacemos.
Para usar DynamoDBLocal, debe seguir estos pasos.
- Obtener Directo DynamoDBLocal Dependencia
- Obtener las dependencias nativas de SQLite4Java
- Configure
sqlite4java.library.path
para mostrar bibliotecas nativas
1. Obtenga Dependencia Direct DynamoDBLocal
Este es el fácil. Necesita este repositorio como se explica en los foros de 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. Obtenga dependencias SQLite4Java nativas
Si no agrega estas dependencias, sus pruebas fallarán con un error interno de 500.
Primero, agregue estas dependencias:
<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>
A continuación, agregue este complemento para obtener dependencias nativas en una carpeta específica:
<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. Establezca sqlite4java.library.path
para mostrar las bibliotecas nativas
Como último paso, debe establecer la propiedad del sistema sqlite4java.library.path
directorio native-libs. Está bien hacer eso justo antes de crear su servidor local.
System.setProperty("sqlite4java.library.path", "native-libs");
Después de estos pasos, puede usar DynamoDBLocal como lo desee. Aquí hay una regla de Junit que crea un servidor local para eso.
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);
}
}
}
Puedes usar esta regla como esta
@RunWith(JUnit4.class)
public class UserDAOImplTest {
@ClassRule
public static final LocalDynamoDBCreationRule dynamoDB = new LocalDynamoDBCreationRule();
}
Puede usar DynamoDB Local como una dependencia de prueba de Maven en su código de prueba, como se muestra en este anuncio . Puedes correr sobre 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();
También puede ejecutar en modo incrustado:
import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
AmazonDynamoDB dynamodb = DynamoDBEmbedded.create();
dynamodb.listTables();