【问题标题】:TypeError: AWS.DynamoDB.DocumentClient is not a constructor when testing with JestTypeError:使用 Jest 进行测试时,AWS.DynamoDB.DocumentClient 不是构造函数
【发布时间】:2020-07-01 08:27:34
【问题描述】:

我正在运行 jest 测试来测试 dynamodb.js 文件和使用 dynamodb.js 文件的 create.js 文件。 create.js 模块是通用的,可以通过构造参数对象并将其传递到任何表中。但是,我收到了以下错误,我需要帮助。

TypeError: AWS.DynamoDB.DocumentClient is not a constructor

__mock__文件夹

const getMock = jest.fn().mockImplementation(() => {
  return {
    promise() {
      return Promise.resolve({});
    }
  };
});

const putMock = jest.fn().mockImplementation(() => {
  return {
    promise() {
      return Promise.resolve({});
    }
  };
});

// eslint-disable-next-line func-names
function DynamoDB() {
  return {
    DocumentClient: jest.fn(() => ({
      get: getMock,
      put: putMock
    }))
  };
}

const AWS = { DynamoDB, getMock, putMock };
module.exports = AWS;

dynamodb.js

const AWS = require('aws-sdk');
const http = require('http');
const https = require('https');
const url = require('url');

module.exports = endpoint => {
  const { protocol } = url.parse(endpoint || '');

  const agentConfig = {
    keepAlive: true,
    keepAliveMsecs: 20000
  };

  const httpOptions =
    protocol === 'http:' ? { agent: new http.Agent(agentConfig) } : { agent: new https.Agent(agentConfig) };

  const db = new AWS.DynamoDB({
    endpoint,
    httpOptions
  });

  const docClient = new AWS.DynamoDB.DocumentClient({
    service: db
  });

  return {
    docClient,
    db
  };
};

dynamodb.spec.js

 
const AWS = require('aws-sdk');
const dynamodb = require('../../../src/dynamodb');

describe('dynamodb.js', () => {
  beforeEach(() => {
    // jest.resetModules();
  });

  test('calls generic-dynamodb-lib dynamodb', async () => {
    dynamodb('http://localhost:8001');

    expect(AWS.DynamoDB).toHaveBeenCalled();
    expect(AWS.DynamoDB.DocumentClient).toHaveBeenCalled();
  });
});

创建.js

// Imports here

const create = async (log, docClient, table, tableRecord) => {
  try {
    await docClient.put({ TableName: table, Item: tableRecord }).promise();
  } catch (error) {
    log.error({ message: 'DynamoDB error', ...error });
    throw Error.internal();
  }

  return tableRecord;
};

module.exports = create;

我也尝试用 doMock 块替换 mock 中的手动模拟,但仍然继续收到上述相同的错误。 一旦我克服了这个问题,考虑到 docClient.js 被传递到函数中,我该如何测试 create.js?非常感谢。

【问题讨论】:

    标签: javascript node.js unit-testing jestjs aws-sdk


    【解决方案1】:

    DocumentClient 应该是静态属性,而它被模拟为实例属性。

    应该是:

    const DynamoDB = jest.fn().mockReturnValue({});
    DynamoDB.DocumentClient = jest.fn().mockReturnValue({
      get: getMock,
      put: putMock
    });
    

    【讨论】:

    • 我现在才看到你的评论。我已经能够使用下面的这种方法来做到这一点:``` const fakePut = jest.fn().mockImplementation(() => { return { promise() { return Promise.resolve({}); } }; } ); const FakeDocumentClient = jest.fn(() => ({ put: fakePut })); AWS.DynamoDB.DocumentClient = FakeDocumentClient; ```
    • 不过,我会尝试您的方法,并让您知道它是否也适用于我。
    【解决方案2】:

    非常感谢您的回复。 在看到这里的回复之前,我已经找到了解决问题的方法。

    我最终不需要在__mock__ 目录中放置任何模拟。

    请查看我提出的测试:

    create.spec.js

    const AWS = require('aws-sdk');
    
    const dynamodb = require('../../../src/dynamodb');
    
    const create = require('../../../src/create');
    
    describe('create.js', () => {
      beforeEach(() => {
        jest.resetModules();
      });
    
      test('calls DocumentClient put with a successful outcome', async () => {
        const log = { error: jest.fn() };
    
        const fakePut = jest.fn().mockImplementation(() => {
          return {
            promise() {
              return Promise.resolve({});
            }
          };
        });
    
        AWS.DynamoDB.DocumentClient = jest.fn(() => ({
          put: fakePut
        }));
    
        const document = {
          brands: ['visa', 'mc', 'amex', 'maestro', 'diners', 'discover', 'jcb']
        };
    
        const { docClient } = dynamodb('https://localhost:8001');
        await create(log, docClient, 'a-table-name', {
          countryCode: 'US',
          merchantAccount: 'MerchantAccountUS',
          expireAt: 1593814944,
          document
        });
    
        expect(create).toEqual(expect.any(Function));
        expect(fakePut).toHaveBeenCalled();
        expect(fakePut).toHaveBeenCalledWith({
          TableName: 'a-table-name',
          Item: {
            countryCode: 'US',
            merchantAccount: 'MerchantAccountUS',
            expireAt: 1593814944,
            document
          }
        });
      });
    
      test('calls DocumentClient put with unsuccessful outcome', async () => {
        const log = { error: jest.fn() };
    
        const fakePut = jest.fn().mockImplementation(() => {
          throw Error.internal();
        });
    
        AWS.DynamoDB.DocumentClient = jest.fn(() => ({
          put: fakePut
        }));
    
        const document = {
          brands: ['visa', 'mc', 'amex', 'maestro', 'diners', 'discover', 'jcb']
        };
    
        const { docClient } = dynamodb('https://localhost:8001');
        let thrownError;
    
        try {
          await create(log, docClient, 'a-table-name', {
            countryCode: 'US',
            merchantAccount: 'MerchantAccountUS',
            expireAt: 1593814944,
            document
          });
        } catch (e) {
          thrownError = e;
        }
    
        expect(create).toEqual(expect.any(Function));
        expect(fakePut).toHaveBeenCalled();
        expect(fakePut).toHaveBeenCalledWith({
          TableName: 'a-table-name',
          Item: {
            countryCode: 'US',
            merchantAccount: 'MerchantAccountUS',
            expireAt: 1593814944,
            document
          }
        });
        expect(thrownError).toEqual(Error.internal());
      });
    });
    

    dynamodb.spec.js

    const AWS = require('aws-sdk');
    const http = require('http');
    const https = require('https');
    const url = require('url');
    const dynamodb = require('../../../src/dynamodb');
    
    const fakeFunction = jest.fn().mockImplementation(() => {});
    
    const FakeDynamoDB = jest.fn(() => ({
      DocumentClient: fakeFunction
    }));
    AWS.DynamoDB = FakeDynamoDB;
    
    const fakeGet = fakeFunction;
    const fakePut = fakeFunction;
    
    const FakeDocumentClient = jest.fn(() => ({
      get: fakeGet,
      put: fakePut
    }));
    AWS.DynamoDB.DocumentClient = FakeDocumentClient;
    
    describe('dynamodb.js', () => {
      beforeEach(() => {
        jest.resetModules();
      });
    
      test('calls DynamoDB and DocumentClient constructors with http protocol and with endpoint present', () => {
        const fakeParse = jest.fn().mockImplementation(() => 'http');
        url.parse = fakeParse;
    
        const fakeHttpAgent = jest.fn().mockImplementation(() => {});
        http.Agent = fakeHttpAgent;
    
        dynamodb('http://localhost:8001');
    
        expect(FakeDynamoDB).toHaveBeenCalled();
        expect(FakeDocumentClient).toHaveBeenCalled();
      });
    
      test('calls DynamoDB and DocumentClient constructors with https protocol and with endpoint present', () => {
        const fakeParse = jest.fn().mockImplementation(() => 'https');
        url.parse = fakeParse;
    
        const fakeHttpsAgent = jest.fn().mockImplementation(() => {});
        https.Agent = fakeHttpsAgent;
    
        dynamodb('https://localhost:8001');
    
        expect(FakeDynamoDB).toHaveBeenCalled();
        expect(FakeDocumentClient).toHaveBeenCalled();
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2020-01-08
      • 2017-07-27
      • 2018-04-05
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-20
      • 1970-01-01
      相关资源
      最近更新 更多