如何开玩笑地模拟 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
我有一个简单的处理程序,调用 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