How to Mock AWS Services in TypeScript
Tags: aws, typescript, testing
Published: 2018-09-10 21:32:13

---
title: How to Mock AWS Services in TypeScript
published: true
description: 
tags: #aws #typescript #testing
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ddl6q28my5aidlgns8an.png
canonical_url: https://blog.kylegalbraith.com/2018/09/10/two-ways-of-mocking-aws-services-in-typescript/
---
I've recently been working on [a new project to automatically convert blog posts to audio](https://www.parler.io/) that has a couple different serverless microservices. 

Each microservice is initialized using the [Serverless Framework](https://serverless.com/) and typically consists of one or more Lambda functions and either an SNS topic, SQS queue, DynamoDB table, or API Gateway endpoint.

I decided to implement each serverless microservice using TypeScript rather than my default of traditional Javascript. I chose this path because I wanted to have static type checking for a more resilient code base.

Typescript is a very cool language and has grown in popularity in recent years. It provides a lot of different benefits outside of just static type checking:

* Optional typings.
* Type inference.
* Access to new ES features. 
* Option to compile to different JS versions.
* Clear library API definitions via `.d.ts`.
* Class and module support.
* A lot of great tooling to support the environment.

In building out these services I ran into a problem that stopped me dead in my tracks for a few hours. I was writing unit tests for a new adapter inside of one of my services that leverages DynamoDB for storage.

To effectively test the adapter I needed to mock the responses from the DynamoDB client inside of the `aws-sdk`. This proved to be a bit more challenging than I originally thought.

Therefore I thought it would be worthwhile to put together a quick blog post on the two methods I found for mocking the aws-sdk.

### Mocking in TypeScript with TypeMoq
There are a lot of fantastic tools for mocking TypeScript. The one I chose for my work was [TypeMoq](https://github.com/florinn/typemoq). It is very similar to the [Moq](https://github.com/moq/moq) library in the .NET framework.

It is fairly simple to get started. Let's say we have a piece of code like the one shown below.

```typescript
export class MessageProcessor {
    conversionAdapter: ConversionAdapter

    constructor(conversionAdapter: ConversionAdapter) {
        this.conversionAdapter = conversionAdapter;
    }

    processJobs(records: IConversionModel[]): Promise<boolean>  {
        return new Promise((resolve, reject) => {
            this.conversionAdapter.convert(record).then((result) => {
                resolve(true);
            }).catch((err) => {
                reject(err);
            });
        });
    }
}
```

This code is calling the `convert` method on a class named `ConversionAdapter`. From the code, we can see that the method returns a `Promise`. We use the result of that promise to resolve our outer promise or reject it if there is an error.

We can set up a test for the `processJobs` method by using TypeMoq to mock the result of the `convert` method on `ConversionAdapter`.

```typescript
describe("MessageProcessor", function () {
    before(function () => {
        this.model = new ConversionModel();
        this.model.url = "url";
        this.model.content = "content";
        this.model.title = "title";
        this.model.userId = "1234-userid";
    });

    it("processJobs success", function (done) => {
        var mockAdapterFactory = TypeMoq.Mock.ofType<IConversionAdapter>(ConversionAdapter);
        mockAdapterFactory.setup(m => m.convert(this.model)).returns(() => Promise.resolve(1));
        
        var processor = new MessageProcessor(mockAdapterFactory.object);
        var pass = [ this.model ];
        processor.processJobs(pass).then((result) => {
            expect(result).to.eql(true);
            done();
        });
    });
});
```

The key here is our setup of `mockAdapterFactory`. We are using `TypeMoq.Mock.ofType<IConversionAdapter>(ConversionAdapter)` to create a mock of our adapter. We then set up the `convert` method to return `Promise.resolve(1)`. 

From there it's just a matter of us passing the actual mock, `mockAdapterFactory.object` into our `MessageProcessor` class.

Now we can wait for our promise to resolve and verify that the result we get back is true.

OK, now we got the basics of mocking in Typescript. Let's move onto how we can mock AWS services like SNS, SQS, or DynamoDB.

### Two ways to mock AWS services in TypeScript
To be clear, there is more than these two ways to mock the `aws-sdk` in TypeScript. These are just two ways I got working and wanted to share my experiences to hopefully save someone time in the future.

Let's give ourselves some context first. Here we have a class, `StorageAdapter`, that is using DynamoDB internally.

```typescript
export class StorageAdapter implements IStorageAdapter {
    dynamoClient: DynamoDB;
    tableName: string;

    constructor(dynamoClient: DynamoDB, tableName: string) {
        this.tableName = tableName;
        this.dynamoClient = dynamoClient;
    }

    readItem(id: string): Promise<DynamoDB.GetItemOutput> {
        return new Promise((resolve, reject) => {
            let itemInput: DynamoDB.Types.GetItemInput = {
                TableName: this.tableName,
                Key: this.setKey(id)
            };

            this.dynamoClient.getItem(itemInput).promise().then((data: PromiseResult<DynamoDB.GetItemOutput, AWSError>) => {
                if (data.$response && data.$response.error != null) {
                    reject(data.$response.error);
                } else {
                    resolve(data.Item);
                }
            });
        });
    }

    private setKey(id: string): Key {
        let keyStruct: Key = {
            "ConversionId": {
                S: id
            }
        }

        return keyStruct;
    }
}
```

Here in `readItem`, we are calling `getItem` on the DynamoDB client from the `aws-sdk`. Additionally, we tell the SDK that we want a promise returned to us by appending `.promise()` at the end of our call.

We then take the result of that call and reject or resolve our outer promise depending on whether there is an error.

Now, let's dive into two ways we can mock `getItem` on the DynamoDB client in order to properly test our code.

#### Method 1: Using TypeMoq
Our first option is to use TypeMoq.

```typescript
describe("StorageAdapter", function () => {
    before(function () => {
    });

    it("readItem correctly", function (done) => {
        var expectedPr: PromiseResult<DynamoDB.GetItemOutput, AWSError> = {
            Item: {
                "ConversionId": {
                    S: "fooid"
                },
                "Email": {
                    S: "kyle@test.com"
                },
                "Status": {
                    S: "Converting"
                },
                "Characters": {
                    N: `${123}`
                },
                "Url": {
                    S: "https://cloudfront.com"
                }
            },
            $response: null
        };
        
        var mockAdapterFactory = TypeMoq.Mock.ofType<DynamoDB>(DynamoDB);
        var mockRequestFactory = TypeMoq.Mock.ofType<Request<DynamoDB.GetItemOutput, AWSError>>(Request);      

        mockRequestFactory.setup(m => m.promise()).returns(() => Promise.resolve(expectedPr));
        mockAdapterFactory.setup(m => m.getItem(TypeMoq.It.isAny())).returns(() => mockRequestFactory.object);

        var storage = new StorageAdapter(mockAdapterFactory.object, "testTable");
        storage.readItem("fooid").then((result) => {
            console.log(result);
        }).catch((err) => {
            console.error(err);
        });
    });
});

```

We first have to set up our DynamoDB mock which is what we see with `mockAdapterFactory`. Then we have to create a mocked `Request` object that `getItem` returns and we can see that with our `mockRequestFactory` variable.

Now we can configure our mocks to return what we need to test our code.

First, we configure `promise()` on `mockRequestFactory` to return a resolved promise with our expected `DynamoDB.GetItemOutput` declared in `expectedPR`.

Next, we configure `getItem()` on `mockAdapterFactory` to return the mocked request we just finished setting up.

From there we just need to pass the actual mock of our DynamoDB client by passing `mockAdapterFactory.object` into our `StorageAdapter`. 

If your keeping track we need four lines of code using TypeMoq in order to mock our `getItem` call on DynamoDB. This is very verbose for writing tests, but it does provide a high level of visibility into what types are being leveraged for this `getItem` call to complete successfully.

Let's explore how we can accomplish the same goal using a different mocking library.

#### Method 2: Using aws-sdk-mock
There is another mocking library, [aws-sdk-mock](https://github.com/dwyl/aws-sdk-mock), that is dedicated to mocking the `aws-sdk`.

We can actually reduce the four lines of code we have with TypeMoq to just one line of code.

```typescript
describe("StorageAdapter", () => {
    before(() => {
    });

    it("readItem correctly", () => {
        var expectedPr: PromiseResult<DynamoDB.GetItemOutput, AWSError> = {
            Item: {
                "ConversionId": {
                    S: "fooid"
                },
                "Email": {
                    S: "kyle@test.com"
                },
                "Status": {
                    S: "Converting"
                },
                "Characters": {
                    N: `${123}`
                },
                "Url": {
                    S: "https://cloudfront.com"
                }
            },
            $response: null
        };
        
        AWSMock.mock('DynamoDB', 'getItem', Promise.resolve(expectedPr));
        var storage = new StorageAdapter(new DynamoDB(), "testTable");
        storage.readItem("fooid").then((result) => {
            console.log(result);
        }).catch((err) => {
            var x = 3;
        });
    });
});

```

Instead of mocking our DynamoDB client, the request, and the promise associated with `getItem`, we can just mock `getItem` and return a resolved promise. There is a lot less set up in order to create a valuable mock and accurately test our `StorageAdapter` class.

This has the benefit of being very concise and clear to follow. However, currently `aws-sdk-mock` does **not** have any TypeScript typings which impacts our IntelliSense during development.

### Recapping mocking AWS in TypeScript
There have been quite a few articles that cover how to mock AWS services, but they often don't incorporate TypeScript. This isn't a problem as anything written for normal JavaScript can be leveraged in our TS world, just without any types. This is what we see with our use of `aws-sdk-mock`.

Testing is key to any production-ready service, even in your low-level adapters that interface with AWS services. However, it can be deceptively tricky to mock AWS services in order to accurately test our code. This is often because the types are more complex, for example, `.getItem().promise()` actually returns a generic type of `PromiseResult<DynamoDB.GetItemOutput, AWSError>`.

What we have demonstrated here, is two approaches to mocking the `aws-sdk`. Our first approach using TypeMoq demonstrated a TypeScript style, using types and incrementally building up our mock. We build up the entire chain of types from the request all the way up to the resolved promise.

The second approach using `aws-sdk-mock` showed how we can mock a single service call with one line of code.

In method one, we have types and verbosity, but sacrifice conciseness by having to build up our mock. Method two, we have conciseness but lose our types and must then know the specific method calls and client declarations. There is no right answer here, both work great depending on what your preference is.

On another note, `aws-sdk-mock` is dedicated to mocking just the `aws-sdk`. Whereas TypeMoq can be used universally throughout our TypeScript tests. In fact, I ended up using both throughout my services. TypeMoq to mock my classes as well as my interfaces and the SDK mock for mocking out the AWS services.

Like most things in developing code, there isn't a single right answer. My hope is that my experience in mocking the `aws-sdk` in TypeScript has given you an example of how you can do the same in your own code.

As always if you have questions or comments related to AWS or this post, please leave a comment below.

### Are you hungry to learn even more about Amazon Web Services?

If you are looking to begin your AWS journey but feel lost on where to start, consider [checking out my course](https://www.kylegalbraith.com/learn-aws). We focus on hosting, securing, and deploying static websites on AWS. Allowing us to learn over 6 different AWS services as we are using them. After you have mastered the basics there we can then dive into **two bonus chapters** to cover more advanced topics like Infrastructure as Code and Continous Deployment.