node.js - 如何对在单独方法中调用的 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
以确保外部库不会造成干扰。但是,无论我尝试了什么,我都无法让它发挥作用。
我试过存根S3
put 对象方法,但无济于事:
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 的调用次数,但我无能为力。
任何人都可以帮忙吗?
解决方案
我遇到了类似的情况,试图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 })
})
})
})
希望有帮助!
推荐阅读
- flutter - 在 Flutter 中下载未知的文件扩展名
- postgresql - PostgreSQL 中是否有任何可信赖的企业级主到主(双向)复制选项
- javascript - 如何在反应标头中显示 3 个组件?似乎它们目前是互斥的
- android - 使用导航组件的深层链接未打开我的目标片段
- .net - AWS DynamoDB 表中的正确分区键
- python - 计算两个日期时间之间的差异?
- javascript - Polymer 3.0 搜索
- python-3.x - python:使用函数的返回值作为类中的值
- openstreetmap - Overpass api查询获取bbox的大陆/地区
- reactjs - 为什么我们需要在 redux thunk 或 saga 中调用 api 为什么不在组件中?