首页 > 解决方案 > 用 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();
  });
});

标签: node.jstypescriptunit-testingjestjsaws-sdk

解决方案


我能够使它以这种方式工作:

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

推荐阅读