我写了一个lambda,如下。
handler.js
const aws = require('aws-sdk');
const dynamoDb = new aws.DynamoDB.DocumentClient();
const testHandler = async event => {
// some code
// ...
const user = await getUser(userId)
// ...
// some code
}
const promisify = foo => new Promise((resolve, reject) => {
foo((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
const getUser = (userId) => promisify(callback =>
dynamoDb.get({
TableName: 'test-table',
Key: {
"PK": `${userId}`,
"SK": `${userId}`
}
}, callback))
.then((user) => {
console.log(`Retrieved user: ${userId}`)
return user
})
module.exports = {
testHandler: testHandler,
getUser: getUser
}
我想编写一个用于测试getUser
函数的单元测试,所以我尝试了以下方法。
handler.test.js
const handler = require('../handler');
const AWS = require('aws-sdk')
const dynamoDbGetParameterPromise = jest.fn().mockReturnValue({
promise: jest.fn().mockResolvedValue({
PK: 'userId-123', SK: 'userId-123'
})
})
AWS.DynamoDB.DocumentClient = jest.fn().mockImplementation(() => ({
get: dynamoDbGetParameterPromise
}))
describe('test getUser', () => {
beforeEach(() => {
jest.resetModules()
});
test('get user success', async () => {
const user = { PK: 'userId-123', SK: 'userId-123' };
const result = await handler.getUser(userId);
expect(result).toEqual(user);
});
});
错误如下。
ConfigError: Missing region in config
105 |
106 | const getUser = (userId) => promisify(callback =>
> 107 | dynamoDb.get({
| ^
108 | TableName: 'test-table',
109 | Key: {
110 | "PK": 'userId-123',
测试似乎仍然在dynamoDb
中使用handler.js
,而不是在测试中进行模拟。
关于如何正确连接模拟程序以测试功能的任何想法? 预先感谢!
答案 0 :(得分:1)
您可以使用jest.mock(moduleName, factory, options)手动模拟aws-sdk
模块。
例如
handler.js
:
const aws = require('aws-sdk');
const dynamoDb = new aws.DynamoDB.DocumentClient();
const promisify = (foo) =>
new Promise((resolve, reject) => {
foo((error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
const getUser = (userId) =>
promisify((callback) =>
dynamoDb.get(
{
TableName: 'test-table',
Key: {
PK: `${userId}`,
SK: `${userId}`,
},
},
callback,
),
).then((user) => {
console.log(`Retrieved user: ${userId}`);
return user;
});
module.exports = { getUser };
handler.test.js
:
const aws = require('aws-sdk');
const { getUser } = require('./handler');
jest.mock('aws-sdk', () => {
const mDocumentClient = { get: jest.fn() };
const mDynamoDB = { DocumentClient: jest.fn(() => mDocumentClient) };
return { DynamoDB: mDynamoDB };
});
const mDynamoDb = new aws.DynamoDB.DocumentClient();
describe('64564233', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should get user', async () => {
const mResult = { name: 'teresa teng' };
mDynamoDb.get.mockImplementationOnce((_, callback) => callback(null, mResult));
const actual = await getUser(1);
expect(actual).toEqual({ name: 'teresa teng' });
expect(mDynamoDb.get).toBeCalledWith(
{
TableName: 'test-table',
Key: {
PK: '1',
SK: '1',
},
},
expect.any(Function),
);
});
it('should handler error', async () => {
const mError = new Error('network');
mDynamoDb.get.mockImplementationOnce((_, callback) => callback(mError));
await expect(getUser(1)).rejects.toThrowError('network');
expect(mDynamoDb.get).toBeCalledWith(
{
TableName: 'test-table',
Key: {
PK: '1',
SK: '1',
},
},
expect.any(Function),
);
});
});
单元测试结果:
PASS src/stackoverflow/64564233/handler.test.js (14.929s)
64564233
✓ should get user (23ms)
✓ should handler error (3ms)
console.log src/stackoverflow/64564233/handler.js:433
Retrieved user: 1
------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
handler.js | 100 | 100 | 100 | 100 | |
------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 17.435s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/64564233
答案 1 :(得分:1)
您可以通过添加来使用jest的自动模拟功能
jest.mock("aws-sdk");
,然后AWS.DynamoDB.DocumentClient
将是一个模拟类,因此您可以模拟它的实现。并且由于我们希望它的get方法成为一个接受任何东西作为第一个参数的函数(因为我们不会在模拟实现中对其进行任何处理)和一个我们希望它被{{1 }}和null
,我们可以这样模拟:
user