Jest mock aws-sdk ReferenceError: Cannot access before initialization
Jest mock aws-sdk ReferenceError: Cannot access before initialization
开玩笑 25.3.0
我正在尝试在我的单元测试中模拟 DynamoDB 依赖性,如下所示:
const { findById } = require('./mymodule');
const mockDynamoDB = { getItem: jest.fn() };
jest.mock('aws-sdk', () => ({
DynamoDB: jest.fn(() => mockDynamoDB)
}));
describe('.', () => {
it('..', () => {
findById('test');
expect(mockDynamoDB.getItem).toBeCalledWith({
TableName: 'table-name',
Key: {
id: { S: 'test' }
}
});
});
});
不幸的是,当我这样做时,出现以下错误:
ReferenceError: Cannot access 'mockDynamoDB' before initialization
奇怪的是,如果我这样做,我可以避免 ReferenceError
:
const mockGetItem = { promise: jest.fn() };
jest.mock('aws-sdk', () => ({
DynamoDB: jest.fn(() => ({
getItem: jest.fn(() => mockGetItem)
})
}));
但这不适合我的测试,因为我无法验证传递给 getItem
函数的参数。
实际测试的代码相当简单,看起来像这样:
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
const toRecord = (item) => ({
id: item.id.S,
name: item.name.S
});
const findById = (id) => (
dynamodb.getItem({
TableName: 'table-name',
Key: {
id: { S: id }
}
}).promise()
.then(result => toRecord(result.Item))
.catch(error => console.log(error)
);
module.exports = {
findById
}
如果有人以前看过这个,或者可以阐明为什么第一个示例失败而第二个示例有效,那将真正帮助我。谢谢。
单元测试解决方案如下:
index.js
:
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const toRecord = (item) => ({
id: item.id.S,
name: item.name.S,
});
const findById = (id) =>
dynamodb
.getItem({
TableName: 'table-name',
Key: {
id: { S: id },
},
})
.promise()
.then((result) => toRecord(result.Item))
.catch((error) => console.log(error));
module.exports = { findById };
index.test.js
:
const { findById } = require('./');
const AWS = require('aws-sdk');
jest.mock('aws-sdk', () => {
const mDynamoDB = { getItem: jest.fn().mockReturnThis(), promise: jest.fn() };
return { DynamoDB: jest.fn(() => mDynamoDB) };
});
describe('61157392', () => {
let dynamodb;
beforeAll(() => {
dynamodb = new AWS.DynamoDB();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
dynamodb.getItem().promise.mockResolvedValueOnce({
Item: {
id: { S: '1' },
name: { S: 'a' },
},
});
const actual = await findById('1');
expect(actual).toEqual({ id: '1', name: 'a' });
expect(dynamodb.getItem).toBeCalledWith({
TableName: 'table-name',
Key: {
id: { S: '1' },
},
});
expect(dynamodb.getItem().promise).toBeCalledTimes(1);
});
});
100% 覆盖率的单元测试结果:
PASS Whosebug/61157392/index.test.js (8.216s)
61157392
✓ should pass (4ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 88.89 | 100 | 75 | 87.5 |
index.js | 88.89 | 100 | 75 | 87.5 | 19
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.559s
源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/61157392
主要问题是:
由于您的 mymodule
是在 before 声明模拟变量之前导入的,因此它也会在 before 运行模拟片段.这就是为什么它声称您的变量尚未声明 - 因为当模拟代码为 运行 时,您的环境无法找到变量声明,即使您 - 视觉上 - 查看它在您的模拟代码段之前声明。
避免此错误的另一种方法是这样做:
const {DynamoDB} from 'aws-sdk';
jest.mock('aws-sdk', () => ({
DynamoDB: () => ({ getItem: jest.fn() })
}));
// At this point, whenever you reference DynamoDB, it's gonna be the mocked version.
// expect(DynamoDB.getItem).toHaveBeenCalled();
开玩笑 25.3.0
我正在尝试在我的单元测试中模拟 DynamoDB 依赖性,如下所示:
const { findById } = require('./mymodule');
const mockDynamoDB = { getItem: jest.fn() };
jest.mock('aws-sdk', () => ({
DynamoDB: jest.fn(() => mockDynamoDB)
}));
describe('.', () => {
it('..', () => {
findById('test');
expect(mockDynamoDB.getItem).toBeCalledWith({
TableName: 'table-name',
Key: {
id: { S: 'test' }
}
});
});
});
不幸的是,当我这样做时,出现以下错误:
ReferenceError: Cannot access 'mockDynamoDB' before initialization
奇怪的是,如果我这样做,我可以避免 ReferenceError
:
const mockGetItem = { promise: jest.fn() };
jest.mock('aws-sdk', () => ({
DynamoDB: jest.fn(() => ({
getItem: jest.fn(() => mockGetItem)
})
}));
但这不适合我的测试,因为我无法验证传递给 getItem
函数的参数。
实际测试的代码相当简单,看起来像这样:
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
const toRecord = (item) => ({
id: item.id.S,
name: item.name.S
});
const findById = (id) => (
dynamodb.getItem({
TableName: 'table-name',
Key: {
id: { S: id }
}
}).promise()
.then(result => toRecord(result.Item))
.catch(error => console.log(error)
);
module.exports = {
findById
}
如果有人以前看过这个,或者可以阐明为什么第一个示例失败而第二个示例有效,那将真正帮助我。谢谢。
单元测试解决方案如下:
index.js
:
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const toRecord = (item) => ({
id: item.id.S,
name: item.name.S,
});
const findById = (id) =>
dynamodb
.getItem({
TableName: 'table-name',
Key: {
id: { S: id },
},
})
.promise()
.then((result) => toRecord(result.Item))
.catch((error) => console.log(error));
module.exports = { findById };
index.test.js
:
const { findById } = require('./');
const AWS = require('aws-sdk');
jest.mock('aws-sdk', () => {
const mDynamoDB = { getItem: jest.fn().mockReturnThis(), promise: jest.fn() };
return { DynamoDB: jest.fn(() => mDynamoDB) };
});
describe('61157392', () => {
let dynamodb;
beforeAll(() => {
dynamodb = new AWS.DynamoDB();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
dynamodb.getItem().promise.mockResolvedValueOnce({
Item: {
id: { S: '1' },
name: { S: 'a' },
},
});
const actual = await findById('1');
expect(actual).toEqual({ id: '1', name: 'a' });
expect(dynamodb.getItem).toBeCalledWith({
TableName: 'table-name',
Key: {
id: { S: '1' },
},
});
expect(dynamodb.getItem().promise).toBeCalledTimes(1);
});
});
100% 覆盖率的单元测试结果:
PASS Whosebug/61157392/index.test.js (8.216s)
61157392
✓ should pass (4ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 88.89 | 100 | 75 | 87.5 |
index.js | 88.89 | 100 | 75 | 87.5 | 19
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.559s
源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/61157392
主要问题是:
由于您的 mymodule
是在 before 声明模拟变量之前导入的,因此它也会在 before 运行模拟片段.这就是为什么它声称您的变量尚未声明 - 因为当模拟代码为 运行 时,您的环境无法找到变量声明,即使您 - 视觉上 - 查看它在您的模拟代码段之前声明。
避免此错误的另一种方法是这样做:
const {DynamoDB} from 'aws-sdk';
jest.mock('aws-sdk', () => ({
DynamoDB: () => ({ getItem: jest.fn() })
}));
// At this point, whenever you reference DynamoDB, it's gonna be the mocked version.
// expect(DynamoDB.getItem).toHaveBeenCalled();