使用 jest 模拟 AWS.DynamoDB.DocumentClient 的构造函数

Posted

技术标签:

【中文标题】使用 jest 模拟 AWS.DynamoDB.DocumentClient 的构造函数【英文标题】:Mock the constructor for AWS.DynamoDB.DocumentClient using jest 【发布时间】:2020-01-08 16:36:56 【问题描述】:

我有一个看起来像这样的函数:

function connect() 
   const secret = 'secret';
   const key = 'key';
   const region = 'region';
   const client = new AWS.DynamoDB(
      secret,
      key,
      region
   );'
   return new AWS.DynamoDB.DocumentClient( service: client )

我想测试函数connect。我已经像这样模拟了 DynamoDB 构造函数:

// See https://***.com/questions/47606545/mock-a-dependencys-constructor-jest
jest.mock('aws-sdk', () => 
  const DynamoDB = jest.fn().mockImplementation(() => 
    return ;
  );
  return 
    DynamoDB,
  ;
);

但是,这意味着DocumentClient 构造函数失败。我该如何模拟呢?

【问题讨论】:

【参考方案1】:

Jest 为运行测试提供 DynamoDB 集成。看this document,看3. Configure DynamoDB client

const DocumentClient = require('aws-sdk/clients/dynamodb');

const isTest = process.env.JEST_WORKER_ID;
const config = 
  convertEmptyValues: true,
  ...(isTest && endpoint: 'localhost:8000', sslEnabled: false, region: 'local-env')
;

const ddb = new DocumentClient(config);

我猜你可以将 DynamoDB 客户端配置抽象出来(如果你还没有)到它自己的模块文件中并导出该客户端,以便在其他地方需要它,当 Jest 测试运行时,客户端被配置为指向您按照 Jest DynamoDB 文档的其他步骤设置的模拟 DynamoDB 服务器/表。

【讨论】:

很高兴知道我们不必编写自己的帮助程序来运行集成测试(就像我一直在做的那样),我宁愿不使用本地发电机服务器单元测试。我认为如果使用 ts-jest,我们可以只使用 jest.mock('aws-sdk') 因为 aws-sdk 现在附带打字稿定义。【参考方案2】:

基于上述 duxtinto 的评论:

在我的情况下(如果我没看错的话,在 OP 的情况下),DynamoDB 不是作为函数调用的,而是一个带有 DocumentClient 字段的对象,所以这对我有用:

jest.mock('aws-sdk', () => 
  return 
    DynamoDB:  // just an object, not a function
      DocumentClient: jest.fn(() => (
        put: mockDynamoDbPut
      ))
    
  );

【讨论】:

【参考方案3】:

在 TypeScript 中使用 jest 对我有用的方法:

// blabla.test.ts
import  DynamoDB  from 'aws-sdk';
import  ConsumerClass  from '../consumer-class';
import  DependencyConsumerClass  from '../dependency-consumer-class';

/*
* Inside consumerClassInstance.save() is calling this.dynamo.putItem(...).promise();
*/
jest.mock('aws-sdk', () => 
    return 
        DynamoDB: jest.fn(() => 
            return 
                putItem: jest.fn(() => 
                    return 
                        promise: jest.fn(() => true)
                    ;
                )
            ;
        )
    ;
);

test('sample test', async () => 
    const dependencyConsumerClass = new DependencyConsumerClass();
    const consumerClassInstance = new ConsumerClass(dependencyConsumerClass, new DynamoDB());
    
    const result = await consumerClassInstance.save();
    console.log(result);
);

【讨论】:

【参考方案4】:

这对我有用:

const mockDynamoDbPut = jest.fn().mockImplementation(() => 
  return 
    promise() 
      return Promise.resolve();
    
  ;
);

jest.doMock('aws-sdk', () => 
  return 
    DynamoDB: jest.fn(() => (
      DocumentClient: jest.fn(() => (
        put: mockDynamoDbPut
      ))
    ))
  ;
);

希望对你也有帮助。

问候,

大卫。

【讨论】:

这给了我错误ConfigError: Missing region in config。任何想法将不胜感激! 当这种情况发生在我身上时,通常与模拟无法以某种方式或在错误的位置工作有关。这意味着 DocumentClient 尝试连接到数据库实例。 在我的情况下(如果我没看错的话,在 OP 的情况下),DynamoDB 不是作为函数调用的,而是一个带有 DocumentClient 字段的对象,所以这对我有用:` jest.mock('aws-sdk', () => return DynamoDB: // 只是一个对象,而不是一个函数 DocumentClient: jest.fn(() => ( put:模拟DynamoDbPut )) ); `【参考方案5】:

DocumentClient 可能会调用一些client 方法,因此只需定义这些方法存根即可。例如,DocumentClient 将在您的代码中使用 batchGetItem

import AWS from 'aws-sdk';

jest.mock('aws-sdk', () => 
  const DynamoDB = jest.fn().mockImplementation(() => 
    return 
      batchGetItem: jest.fn(),
    ;
  );
  return 
    DynamoDB,
  ;
);

// you could inspect the mock
console.log(new AWS.DynamoDB( ... ));

【讨论】:

以上是关于使用 jest 模拟 AWS.DynamoDB.DocumentClient 的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

Jest 手动模拟在 CRA 中不使用模拟文件

使用 jest.mock('axios') 时如何模拟拦截器?

如何使用 Jest 模拟异步函数

在 Typescript 中使用 Jest + Supertest 进行模拟

手动模拟不适用于 Jest

使用 Typescript 从 Jest 手动模拟中导入函数