我正在尝试模拟一个模块,这里是来自 aws-sdk 的 S3。
我能让它工作的唯一方法是这样的:
jest.mock('aws-sdk', () => {
return {
S3: () => ({
putObject: jest.fn()
})
};
});
问题是我无法访问 S3 或 putObject 作为模拟变量,我可以检查是否出于测试目的而调用。
所以我想做这样的事情:
const putObject = jest.fn();
jest.mock('aws-sdk', () => {
return { S3: () => ({ putObject }) };
});
我总是对其他模块这样做,它工作得很好,它甚至适用于 lambda,但不适用于这种情况。
对我来说,这两个代码看起来完全相同,所以我真的不明白发生了什么以及为什么它的工作方式不完全相同。
当我在我想要测试的代码中控制台记录 s3 时,我得到:
{ putObject: 未定义 }
此外,我使用 TypeScript,因此我不能只导入测试文件中的模块并模拟它(如果它不是模拟变量)。
感谢您的帮助!
编辑:
这是一个可重现的最小问题示例:
上传文件.ts
import AWS from 'aws-sdk';
const s3 = new AWS.S3();
export const uploadFile = async (key, body) => {
try {
await s3
.putObject({
Bucket: 'myBucket',
Key: key,
Body: body,
})
.promise();
} catch (error) {
console.log(error);
}
};
uploadFile.test.ts
import { uploadFile } from './uploadFile';
const mockPutObject = jest.fn(() => ({ promise: jest.fn() }));
jest.mock('aws-sdk', () => {
return { S3: () => ({ putObject: mockPutObject }) };
});
describe('Test uploadFile', () => {
it('should call putObject', () => {
uploadFile('key', { test: 'test' });
expect(mockPutObject).toHaveBeenCalled();
});
});
最佳答案
我能够以这种方式使其工作:
import * as AWS from 'aws-sdk';
import { uploadFile } from '.';
const mockPutObject = jest.fn().mockImplementation((data) => {
return {
promise: () => jest.fn()
}
});
jest.mock('aws-sdk', () => {
return {
S3: function () {
return {
putObject: (data: any) => mockPutObject(data)
}
}
};
});
describe('Test uploadFile', () => {
it('should call putObject', () => {
uploadFile('key', { test: 'test' });
expect(mockPutObject).toHaveBeenCalledTimes(1);
expect(mockPutObject).toHaveBeenCalledWith({
Bucket: 'myBucket',
Key: 'key',
Body: {
test: 'test'
},
});
});
});
有一些您可能不会遇到的挑战:
- AWS.S3 是一个具有构造函数的类,但我找不到有效的 tsconfig 或 babel 配置。因此我将一些
() => {...}
替换为function () { ... }
- 开 Jest 提升属性的方式使得返回
mockPutObject
变得很棘手,因为它在构建模拟时尚未初始化 - 模拟还需要返回
promise()
模拟才能与您的index.ts
配合使用
关于node.js - 使用 Jest 模拟模块无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69116322/