【问题标题】:Mocking two S3 API calls in the same AWS Lambda function using Jest使用 Jest 在同一个 AWS Lambda 函数中模拟两个 S3 API 调用
【发布时间】:2020-08-26 09:41:13
【问题描述】:

我试图在同一个 Lambda 函数中模拟两个 S3 调用,但似乎收到拒绝访问错误,所以这让我相信 S3 调用没有被模拟。我当前使用的语法在仅模拟函数中的一个 S3 调用时有效,但我当前正在测试的函数有两个 S3 调用(deleteObject 和 putObject)。

这是我的模拟代码:

 const putObjectMock = jest.fn(() => ({
      promise: jest.fn(),
 }));

 const deleteObjectMock = jest.fn(() => ({
      promise: jest.fn(),
 })));

 jest.mock("aws-sdk", () => ({
      S3: jest.fn(() => ({
           deleteObject: deleteObjectMock,
           putObject: putObjectMock,
      })),
 }));

我的测试:

 const newHandler = Handler.handler
 const returnValue = await handler ({
      queryStringParameters: {
           eventListValue: "test",
           eventListName: "test2",
      body: {newStuff: "stuff goes here", eventList: [] },
 });
 expect(returnValue).toEqual({
      statusCode:200,
      headers: {
           "Access-Control-Allow-Origin": "*",
           "Access-Control-Allow-Credentials": true,
      },
      body: undefined
 })
 });

文件中包含两个 S3 调用的部分:

 if(event.queryStringParameters.value){
      await s3.deleteObject({Bucket: "my-bucket-name", Key: "name-of-object", 
 }).promise()
 }

 const putObjectResponse = await s3.putObject({Bucket: "my-bucket-name", Key: 
 "name-of-object",
  ContentType: "application/json", Body: event.body}).promise();

当我尝试测试时返回拒绝访问。任何帮助都会很棒。

【问题讨论】:

  • 嗨,Richard - 测试文件中的包导入顺序是什么?
  • 处理程序导入在模拟之后。我尝试将导入移动到模拟之前,但仍然出现拒绝访问错误
  • 其实,我知道我哪里出错了。我将我的包导入为 aws-sdk/clients/s3 而不仅仅是 aws-sdk。谢谢你帮我找对了地方,哈哈@jamespeiris
  • 太棒了!很高兴你对它进行了排序@RichardDesouza
  • 是否值得创建自己的答案来支持顶级导入​​而不是特定服务导入然后接受它,以便其他人可以从这种见解中受益?

标签: javascript amazon-s3 aws-lambda jestjs


【解决方案1】:

这里是单元测试解决方案:

handler.js:

import AWS from 'aws-sdk';

const s3 = new AWS.S3();

export async function handler(event) {
  if (event.queryStringParameters.value) {
    await s3.deleteObject({ Bucket: 'my-bucket-name', Key: 'name-of-object' }).promise();
  }

  const putObjectResponse = await s3
    .putObject({ Bucket: 'my-bucket-name', Key: 'name-of-object', ContentType: 'application/json', Body: event.body })
    .promise();

  return putObjectResponse;
}

handler.test.js:

import { handler } from './handler';
import AWSMock from 'aws-sdk';

jest.mock('aws-sdk', () => {
  const putObjectOutputMock = {
    promise: jest.fn(),
  };
  const putObjectMock = jest.fn(() => putObjectOutputMock);

  const deleteObjectOutputMock = {
    promise: jest.fn(),
  };
  const deleteObjectMock = jest.fn(() => deleteObjectOutputMock);

  const mS3 = {
    deleteObject: deleteObjectMock,
    putObject: putObjectMock,
  };
  return { S3: jest.fn(() => mS3) };
});

describe('61719699', () => {
  it('should delete object and put object', async () => {
    const mS3 = new AWSMock.S3();
    const mPutObjectResponse = {
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': true,
      },
      body: undefined,
    };
    mS3.putObject().promise.mockResolvedValueOnce(mPutObjectResponse);

    const mEvent = { queryStringParameters: { value: 'test' }, body: { newStuff: 'stuff goes here', eventList: [] } };
    const returnValue = await handler(mEvent);
    expect(returnValue).toEqual({
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': true,
      },
      body: undefined,
    });
    expect(mS3.deleteObject).toBeCalledWith({ Bucket: 'my-bucket-name', Key: 'name-of-object' });
    expect(mS3.deleteObject().promise).toBeCalled();
    expect(mS3.putObject).toBeCalledWith({
      Bucket: 'my-bucket-name',
      Key: 'name-of-object',
      ContentType: 'application/json',
      Body: { newStuff: 'stuff goes here', eventList: [] },
    });
  });
});

带有覆盖率报告的单元测试结果:

 PASS  stackoverflow/61719699/handler.test.js (10.22s)
  61719699
    ✓ should delete object and put object (7ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |    66.67 |     100 |     100 |                   
 handler.js |     100 |    66.67 |     100 |     100 | 6                 
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.94s

【讨论】:

    【解决方案2】:

    问题是因为我在代码文件中使用了特定的服务导入而不是顶级导入。

    改变了

     const S3 = require("aws-sdk/clients/s3");
    

     const AWS = require("aws-sdk");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-08
      • 1970-01-01
      • 2019-05-22
      • 1970-01-01
      • 1970-01-01
      • 2018-08-21
      • 2020-07-15
      • 1970-01-01
      相关资源
      最近更新 更多