首页 > 解决方案 > 如何对在单独方法中调用的 AWS 开发工具包方法进行单元测试?

问题描述

我目前正在编写一段代码,它只是将文件上传到 S3 存储桶。这是一个用 Typescript 编写的无服务器 NodeJS 项目。对于测试,我正在使用 Mocha、Chai,并尝试使用 SinonJS。

我有一个类,其方法将缓冲区作为文件上传到 S3:

import { S3 } from "aws-sdk"
import { S3UploadError } from "../errors/S3UploadError"

/**
 * This class provides a means of interacting with S3
 *
 * @export
 * @class AWSS3Manager
 */
export class AWSS3Manager {
    /**
     * Instance of S3
     *
     * @private
     * @type {S3}
     * @memberof AWSS3Manager
     */
    private s3: S3

    /**
     * Creates an instance of AWSS3Manager.
     *
     * @memberof AWSS3Manager
     */
    public constructor() {
        this.s3 = new S3()
    }

    /**
     * Upload a file to bucket on S3 by using a buffer
     *
     * @param {Buffer} body
     * @param {string} bucketName
     * @param {string} fileName
     * @returns {Promise<PromiseResult<S3.PutObjectOutput, S3UploadError>>}
     * @memberof AWSS3Manager
     */
    public async upload(body: Buffer, bucketName: string, fileName: string) {
        const params = {
            Body: body,
            Bucket: bucketName,
            Key: fileName,
        }

        try {
            return await this.s3.putObject(params).promise()
        } catch (err) {
            console.log(err)
            throw new S3UploadError()
        }
    }
}

我什至不确定这是否是正确的做法,但我想测试upload上述类的方法。在我看来,要做到这一点,我需要模拟响应,S3.putObject以确保外部库不会造成干扰。但是,无论我尝试了什么,我都无法让它发挥作用。

我试过存根S3put 对象方法,但无济于事:

chai.should()
const assert = chai.assert
const expect = chai.expect
const s3manager = new AWSS3Manager()
let sandbox: sinon.SinonSandbox
let spy

describe("AWSS3Manager behaves as expected", () => {
    beforeEach(() => {
        sandbox = sinon.createSandbox()
        spy = sinon.spy()

    })
    afterEach(() => {
        // Restore the default sandbox here
        sandbox.restore()
    })

    it("Uploads a file correctly to S3", async () => {
        const putObjectStub = sinon.stub(S3.prototype, "putObject")
        putObjectStub.yields("ERROR", 'data')
        //const uploadStub = sandbox.stub(s3manager, "upload").resolves("Yup")
        //sandbox.stub(AWS, "S3").resolves('HEYY')
        const test = await s3manager.upload(new Buffer("ddds"), "TestBucket", "Test")
        assert(putObjectStub.called)
    })
})

我已经尝试对 S3 方法进行存根,并且还对自身的上传方法进行存根,并查看对 putObject 的调用次数,但我无能为力。

任何人都可以帮忙吗?

标签: node.jstypescriptunit-testingaws-sdksinon

解决方案


我遇到了类似的情况,试图putObject在一个实例上取消调用,S3然后我返回链接与.promise(). 见下文:

export class UploadService {
  s3: S3

  constructor() {
    this.s3 = new S3({ region: 'us-west-2' })
  }

  upload({ data, path }: { data: string, path: string }) {
    const uploadParams = {
      Body: data,
      Bucket: bucketName, // defined elsewhere
      Key: path
    }
    return this.s3.putObject(uploadParams).promise()
  }
}

我深入研究了aws-sdk定义并提出了这个测试设置——我不喜欢它,因为它有点暴露了你不应该考虑的 sdk 的胆量,但它通过了打字稿编译器并完成了工作♂️</p>

import { expect } from 'chai'
import * as sinon from 'sinon'
import { UploadService } from '../../src/services/upload_service'
import { Request, Service } from 'aws-sdk'

describe('UploadService', () => {
  const uploadService = new UploadService()
  let uploadStub: sinon.SinonStub

  describe('#upload', () => {
    beforeEach(() => {
      uploadStub = sinon
        .stub(uploadService.s3, 'putObject')
        .returns(new Request(new Service(), 'put'))
    })
    it('uploads the data to the specified path in S3', async () => {
      const data = '{"cool": "data"}'
      const path = 'my/cool/file/path'

      await uploadService.upload({ data, path })

      expect(uploadStub).to.have.been.calledOnceWith({ data, path })
    })
  })
})

希望有帮助!


推荐阅读