Automated Testing Using Gradle, JUnit and DynamoDB Local

Recently, I’ve been working on an open-source project (Todo) that uses HSQL as an in-memory embedded database. However, I’d prefer to migrate to a NoSQL database for production. Our company already uses Amazon Web Services (AWS), so I’ve decided to go with DynamoDB. Since our company is frugal, I wanted to test our code using DynamoDB Local, which is free of charge and doesn’t require an internet connection. However, unlike the automatic configuration of HSQL in a Spring Boot app, getting DynamoDB Local to run properly during tests requires additional configuration in your build script and test cases.

In this post, I’m going to outline the steps for configuring and running a local instance of DynamoDB in your JUnit tests. We’ll begin with the Gradle dependencies and tasks.

Gradle Dependencies

In the Gradle build file, configure the AWS custom repository for DynamoDB Local.

repositories {
   jcenter()

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

Then add the following dependencies:

dependencies {
    // AWS dynamodb
    compile group: 'com.amazonaws', name: 'aws-java-sdk-dynamodb', version: '1.11.213'

    // Use JUnit test framework
    testCompile 'junit:junit:4.12'
    
    //Local DynamoDB
    testCompile "com.amazonaws:DynamoDBLocal:1.+"
    
    //SQLite4Java, required by local DynamoDB
    testCompile group: 'com.almworks.sqlite4java', name: 'sqlite4java', version: '1.0.392'    
}

 

Gradle Tasks

Next, add the following tasks to the Gradle build file:

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

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

 

JUnit Test Case

In your test case, I recommend configuring and running DynamoDB Local before any tests are executed and shutting it down after the tests have completed. You’ll also want to create your tables before executing your tests. This can be achieved by annotating a public static method in your test class with @BeforeClass.

Note: sServer and sClient are static fields in your test class.

@BeforeClass
public static void runDynamoDB() {

  //Need to set the SQLite4Java library path to avoid a linker error
  System.setProperty("sqlite4java.library.path", "./build/libs/");

  // Create an in-memory and in-process instance of DynamoDB Local that runs over HTTP
  final String[] localArgs = { "-inMemory" };

  try {
	sServer = ServerRunner.createServerFromCommandLineArgs(localArgs);
	sServer.start();

  } catch (Exception e) {
	e.printStackTrace();
 	Assert.fail(e.getMessage());
	return;
  }

  createAmazonDynamoDBClient();

  createMyTables();
}
	
private static void createAmazonDynamoDBClient() {
  sClient = AmazonDynamoDBClientBuilder.standard()
	        .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
	        .build();
}

private static void createMyTables() {
	//Create task tables
  DynamoDBMapper mapper = new DynamoDBMapper(sClient);
  CreateTableRequest tableRequest = mapper.generateCreateTableRequest(MyItemOne.class);
  tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
  sClient.createTable(tableRequest);

  tableRequest = mapper.generateCreateTableRequest(MyItemTwo.class);
  tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
  sClient.createTable(tableRequest);

  tableRequest = mapper.generateCreateTableRequest(MyItemThree.class);
  tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
  sClient.createTable(tableRequest);
}

Then after the tests have completed, you’ll want to ensure that the database is shutdown by by annotating a public static method in your test class with @AfterClass.

@AfterClass
public static void shutdownDynamoDB() {
  if(sServer != null) {
     try {
          sServer.stop();
     } catch (Exception e) {
	  e.printStackTrace();
     }
  }
}

I hope these steps help you to more easily implement local automated tests of your DynamoDB code. Let me know if you have any feedback.

References:

Stack Overflow, https://stackoverflow.com/a/39086207/314897

Stack Overflow, https://stackoverflow.com/a/31845157/314897

Testing Excellence, https://www.testingexcellence.com/unsatisfiedlinkerror-sqlite4java-jar-mac-os-x

Advertisements
Automated Testing Using Gradle, JUnit and DynamoDB Local

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s