node.js - 使用 Jest 模拟模块无法正常工作

标签 node.js typescript unit-testing jestjs aws-sdk

我正在尝试模拟一个模块,这里是来自 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/

相关文章:

node.js - 为 Gitlab CI Dockerizing Nodejs 依赖

typescript - 不一致的 TypeScript 行为

unit-testing - Visual Studio 中的测试 session 窗口 (Resharper) 中的 "Success: Test not run"

java - 如何在 JMockit 中模拟具有 void 返回类型的方法?

node.js - 安装的 npm 安装的模块无法被 Angular 识别

node.js - 在 ConditionalOperator 设置为 OR 的情况下扫描 DynamoDB 仍执行 AND

javascript - 根据共同属性合并 2 个 json 数组对象

typescript - 如何在 Angular2 Beta 中使用 RouteData?

javascript - 使用 'document.querySelector' 查找元素后,“单击”功能在 typescript/angular 中不起作用

unit-testing - 在 Visual Studio Code 中调试 Go 测试