Mock DynamoDB Services

We all understand the importance of mocking real services. Without moking, a service can give unexpected result after a few update and delete operations. With mocking, the result of GET will never change, no matter how many times you UPDATE.

The purpose of this article is to explain how to create mocked DynamoDb web services. Though some of the scenarios are not valid for functional tests they are explained for learning purpose only.

Prerequisite

We’re using stubmatic npm package to create mock service. But, you may choose any method of your choice.

Stubmatic is designed specially for testing. It gives many advance features to mock web services. In stubmatic, we create a request-response mapping file which is easy enough to understand. The stub data can be exterlized to the file system.

npm i -g stubmatic

Let’s Mock

Before we jump to a particular scenario, please remember that DynamoDB service expect following headers with valid values;

  • x-amz-target
  • authorization

So we’ll confirm in our mocks that these headers are coming in request. However, we’ll not check for their valid values.

Create a file say mapping.yaml and copy paste the code mentioned in each scenario.

  1. Scenario: mandatory header ‘x-amz-target’ is missing

Below mapping will match a request without x-amz-target header.

-  request:
method: POST
url: /dynamodb
headers:
x-amz-target: ^

response:
body: >
{
"__type": "com.amazonaws.dynamodb.v20120810#InternalFailure",
"message": "The request processing has failed because of an unknown error, exception or failure."
}
status: 500
headers:
Content-type: application/json

As you’ll be trusting on a db client already tested, you’ll not need to test this scenario in your FTs. Similarliy, you can check for authorization header.

2. Scenario: table doesn’t exist

This is another unfit scenario for the FTs so we’re not creating mapping for this. However, this is the response received from DynamoDB with status 400 when the table name mentioned in any request is not created yet.

{
"__type": "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
"message": "Cannot do operations on a non-existent table"

3. Scenario: key doesn’t exist

This is one more mistake we may do. DynamoDb returns following response when they key used in the query/request doesn’t match with the key created for the table.

{
"__type": "com.amazon.coral.validate#ValidationException",
"message": "One of the required keys was not given a value"
}

I don’t see any valid case when you should mock such scenarios.

4. Scenario: data doesn’t exist

This is the perfect case to test in your functional tests when there is no data present against the key you passed.

-  request:
method: POST
url: /dynamodb
headers:
content-type: application/x-amz-json-1.0
x-amz-target: .*GetItem
authorization: .*
post: "Key":{"user_id":{"S":"amitgupta9"}}
   response:
body: {}
state:
headers:
Content-type: application/json

Though it depends on the business scenario but you should always has one to one mapping between the request and response.

5. Scenario: return some data

-  request:
method: POST
url: /dynamodb
headers:
content-type: application/x-amz-json-1.0
x-amz-target: .*GetItem
authorization: .*
post: "Key":{"user_id":{"S":"amitgupta_official"}}
response:
body: >
{
"Item": {
"user_id": {
"S": "amitgupta_official"
},
"name": {
"S": "amit gupta"
},
"website": {
"S": "https://amitkumargupta.work"
}
}
}
state:
headers:
Content-type: application/json

6. Scenario: put some data

-  request:
method: POST
url: /dynamodb
headers:
content-type: application/x-amz-json-1.0
x-amz-target: .*PutItem
authorization: .*
post: "Item":{"user_id":{"S":"amitgupta9"}
response:
body: {}
state:
headers:
Content-type: application/json

Your mapping.yaml is having 5 mappings at this time. Now you have to just run the stubmatic to read the mappings and you’re all set. Create a config file and mentioned it in following command to run your mocked DynamoDB server;

$ stubmatic -p 8000 -h localhost -c config.json

You can skip -h as localhost is by default.

If you’re running the DynamoDB locally, run the following command once you download it;

$ java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

You can also install npm package dynamodb-admin. It’ll provide a GUI running in browser to explore the tables and data in DynamoDB.

In last

What if we’ve missed some scenarios? Run the stubmatic as proxy to debug passing traffic and create the stubs based on that. For this, run you application to connect to DynamoDB on port 8001. But run the DynamoDB locally on port 8000. Now run the following command from any folder;

$ stubmatic -v --debug -p 8001 --to http://localhost:8000

In above command, stubmatic will run in debug mode on port 8001 and pass all the traffic to DynamoDb service running on localhost:8000. It’ll log all request and response on the console.

Please leave comments with your doubts and queries. I would be happy to solve them.

If you like this article, please clap. You can clap many times. It doesn’t require functional testing.

Feedback

Feedbacks are important to understand how can I improve and bring more useful materials. Please clap this article, comment here, or please give a star to stubmatic github repository.