如何开玩笑地模拟 dynamoDB 调用?

How to mock dynamoDB call with jest?

我有一个简单的处理程序,调用 getData 在单独的文件中定义

export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  let respData = await new DynamoDBClient().getData(123);
  return {
    statusCode: 200,
    body: JSON.stringify(respData),
  };
};

在我的 DynamoDB class 中,我有以下内容。

import { DynamoDB } from 'aws-sdk';
export default class DynamoDBClient {
private config: Config;
private client: DynamoDB.DocumentClient;

constructor() {
  this.config = getConfig();

  const dynamoDBClientConfig = this.config.mockDynamoDBEndpoint
  ? {
      endpoint: this.config.mockDynamoDBEndpoint,
      sslEnabled: false,
      region: 'local'
    }
  : undefined;

 this.client = new DynamoDB.DocumentClient(dynamoDBClientConfig);
}
// function
getData= async (id: string): Promise<any> => {
 const response = await this.client
  .query({
    TableName: tableName,
    IndexName: tableIndex,
    KeyConditionExpression: 'id= :id',
    ExpressionAttributeValues: {
      ':id': id
    }
  })
  .promise();
 return response;
}
}

我的测试用例

describe('DynamoDB', () => {
test('should return no data', async () => {
    
    const spy = jest.spyOn(DynamoDBClient, 'getData').mockImplementation(() => jest.fn(() => {
      return Promise.resolve({});
  }));
    const actual = await handler(event);
    console.log(actual);

    expect(actual).toEqual({ statusCode: 400, body: JSON.stringify({ }) });
  });
 });

您使用 属性 初始化语法定义了 .getData() 方法。它将绑定到 class 实例。由于 handler 函数通过 import 语句依赖于 DynamoDBClient class,因此无法在测试用例中创建实例并将其传递给 handler 时调用它。

您可以模拟 aws-sdk 模块和 DynamoDB.DocumentClient class 及其实例。

DynamoDBClient.ts:

import { DynamoDB } from 'aws-sdk';

function getConfig() {
  return { mockDynamoDBEndpoint: '' };
}
interface Config {
  mockDynamoDBEndpoint: string;
}

export default class DynamoDBClient {
  private config: Config;
  private client: DynamoDB.DocumentClient;

  constructor() {
    this.config = getConfig();

    const dynamoDBClientConfig = this.config.mockDynamoDBEndpoint
      ? {
          endpoint: this.config.mockDynamoDBEndpoint,
          sslEnabled: false,
          region: 'local',
        }
      : undefined;

    this.client = new DynamoDB.DocumentClient(dynamoDBClientConfig);
  }

  getData = async (id: string): Promise<any> => {
    const response = await this.client
      .query({
        TableName: 'tableName',
        IndexName: 'tableIndex',
        KeyConditionExpression: 'id= :id',
        ExpressionAttributeValues: {
          ':id': id,
        },
      })
      .promise();
    return response;
  };
}

handler.ts:

import DynamoDBClient from './DynamoDBClient';

interface APIGatewayProxyEvent {}
interface APIGatewayProxyResult {}

export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  let respData = await new DynamoDBClient().getData('123');
  return { statusCode: 200, body: JSON.stringify(respData) };
};

handler.test.ts:

import { handler } from './handler';
import { DynamoDB } from 'aws-sdk';

const mDocumentClientInstance = {
  query: jest.fn().mockReturnThis(),
  promise: jest.fn(),
};
jest.mock('aws-sdk', () => {
  return {
    DynamoDB: {
      DocumentClient: jest.fn(() => mDocumentClientInstance),
    },
  };
});

describe('69475890', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });
  test('should pass', async () => {
    mDocumentClientInstance.promise.mockResolvedValueOnce({});
    const event = {};
    const actual = await handler(event);
    expect(actual).toEqual({ statusCode: 200, body: JSON.stringify({}) });
    expect(DynamoDB.DocumentClient).toBeCalled();
    expect(mDocumentClientInstance.query).toBeCalledWith({
      TableName: 'tableName',
      IndexName: 'tableIndex',
      KeyConditionExpression: 'id= :id',
      ExpressionAttributeValues: {
        ':id': '123',
      },
    });
    expect(mDocumentClientInstance.promise).toBeCalled();
  });
});

测试结果:

 PASS  examples/69475890/handler.test.ts (8.642 s)
  69475890
    ✓ should pass (4 ms)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |     100 |       50 |     100 |     100 |                   
 DynamoDBClient.ts |     100 |       50 |     100 |     100 | 18                
 handler.ts        |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.231 s