简体   繁体   中英

How to mock typescript services and functions that use AWS resources?

I am having a Typescript backend structure and I want to create unit tests for all the functionalities. I am using JEST and aws-skd-mock for mocking AWS. I have tried some things but it seems I am not doing the right thing.

I have this service where I am getting a parameter from ParamterStore (amazon.service.ts) :

import * as AWS from "aws-sdk";

export class AmazonService {

  parameterStore: AWS.SSM;

  constructor() {
    this.parameterStore = new AWS.SSM();
  }

  async getParam(param) {
    let self = this;
    console.log('IN getPARAM', param);
    return new Promise(function(resolve, reject){
      self.parameterStore.getParameter({
        Name: param,
        WithDecryption: true
      }, function (err, data) {
        if (err) {
          console.log('Error ', err);
          return resolve({Error: 'ParameterNotFound'})
        }
        console.log('RES ', data.Parameter.Value);
        return resolve(data.Parameter.Value)
      })
    })
  }

}

Then, I mock whole amazon.service file, I mock SSM.getParameter with response in my test file (amazon.service.spect.ts):

import * as AWSMock from "aws-sdk-mock";
import * as AWS from "aws-sdk";
import {AmazonService} from "./amazon.service";


jest.mock('./amazon.service');

describe('amazon service mock', () => {
  let amazonService: AmazonService;

  it('should get Parameter from Parameter Store', async () => {
    const ssmGetParameterPromise = jest.fn().mockReturnValue({
      promise: jest.fn().mockResolvedValue({
        Parameter: {
          Name: 'NAME',
          Type: 'SecureString',
          Value: 'VALUE',
          Version: 1,
          LastModifiedDate: 1546551668.495,
          ARN: 'arn:aws:ssm:eu-test-1:123:NAME'
        }
      })
    });
    AWSMock.setSDKInstance(AWS);
    AWSMock.mock('SSM', 'GetParameter', ssmGetParameterPromise);
    amazonService = new AmazonService();

    console.log(await amazonService.getParam('NAME'))

    await expect(amazonService.getParam('NAME')).resolves.toBe('VALUE')
  })
});

With this I get undefined when amazonService.getParam is called.

As I looked in the examples they are initializing new AWS.SSM() right after is mocked and call it from test, but I want to achieve that by calling my function. It seems like SSM is not mocked when my function is called.

Any suggestions how to do this right?

You don't need to mock ./amazon.service.ts module. Here is the unit test solution without using aws-sdk-mock .

Eg

amazon.service.ts :

import * as AWS from 'aws-sdk';

export class AmazonService {
  parameterStore: AWS.SSM;

  constructor() {
    this.parameterStore = new AWS.SSM();
  }

  async getParam(param) {
    let self = this;
    console.log('IN getPARAM', param);
    return new Promise(function (resolve, reject) {
      self.parameterStore.getParameter(
        {
          Name: param,
          WithDecryption: true,
        },
        function (err, data) {
          if (err) {
            console.log('Error ', err);
            return resolve({ Error: 'ParameterNotFound' });
          }
          console.log('RES ', data.Parameter!.Value);
          return resolve(data.Parameter!.Value);
        },
      );
    });
  }
}

amazon.service.spec.ts :

import * as AWS from 'aws-sdk';
import { AmazonService } from './amazon.service';
import { mocked } from 'ts-jest/utils';
import { AWSError } from 'aws-sdk';
import { GetParameterResult } from 'aws-sdk/clients/ssm';

jest.mock('aws-sdk', () => {
  const mSSMInstance = {
    getParameter: jest.fn(),
  };
  const mSSM = jest.fn(() => mSSMInstance);

  return { SSM: mSSM };
});

describe('amazon service mock', () => {
  let amazonService: AmazonService;

  it('should get Parameter from Parameter Store', async () => {
    amazonService = new AmazonService();
    expect(AWS.SSM).toBeCalled();
    const mSSMInstance = new AWS.SSM();
    const mData = {
      Parameter: {
        Name: 'NAME',
        Type: 'SecureString',
        Value: 'VALUE',
        Version: 1,
        LastModifiedDate: new Date(1995, 11, 17),
        ARN: 'arn:aws:ssm:eu-test-1:123:NAME',
      },
    };
    mocked(mSSMInstance.getParameter).mockImplementationOnce(
      (params, callback?: (err: AWSError | null, data: GetParameterResult) => void): any => {
        if (callback) {
          callback(null, mData);
        }
      },
    );
    const actual = await amazonService.getParam('NAME');
    expect(actual).toBe('VALUE');
  });
});

unit test result with coverage report:

 PASS  stackoverflow/61871955/amazon.service.spec.ts (9.613s)
  amazon service mock
    ✓ should get Parameter from Parameter Store (19ms)

  console.log
    IN getPARAM NAME

      at AmazonService.<anonymous> (stackoverflow/61871955/amazon.service.ts:12:13)

  console.log
    RES  VALUE

      at stackoverflow/61871955/amazon.service.ts:24:19

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   86.67 |       50 |     100 |   85.71 |                   
 amazon.service.ts |   86.67 |       50 |     100 |   85.71 | 21-22             
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.925s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM