node.js - 用 Jest 模拟模块无法正常工作
问题描述
我正在尝试模拟一个模块,这里是来自 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: undefined }
另外,我使用 TypeScript,所以如果它不是模拟变量,我不能只导入测试文件中的模块和 mockReturnValue 它。
谢谢你的帮助!
编辑:
这是该问题的可重现的最小示例:
上传文件.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);
}
};
上传文件.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 配置。因此我更换了一些
() => {...}
tofunction () { ... }
- 开玩笑提升属性的方式使得返回它很棘手,
mockPutObject
因为它在构建模拟时尚未初始化 - 模拟需要返回
promise()
模拟以及与您的工作index.ts
推荐阅读
- java - 在 OkHttpClient 握手中使用 Java 注册的客户端身份验证证书
- sqlite - 如何使用 Diesel 将 i64 与 Insertable 结合使用
- .net-core - 构建主项目时,运行时标识符在依赖项目中不可用
- ruby-on-rails - 如何访问erb文件中字符串内的Ruby对象
- ionic4 - 适用于 Android 的 ionic 4 插入模式画中画
- node.js - 使用 Mongoose 将唯一对象添加到 MongoDB 中的数组中
- node.js - 在 Heroku 中访问 Vue 应用程序中的环境变量
- python - 未解决的导入“youtube_search”discord.py 视觉工作室
- java - 在 RecyclerView 添加 onClick 打开 RecyclerView 项的 URL
- azure - Azure 数据工厂中“源”列/字段中的混合属性