首页 > 解决方案 > 如何在 mocha 中测试 aws S3

问题描述

这是我第一次尝试 Mocha/Chai 测试。使用 aws S3 在 mocha 中进行集成测试的最佳方法是什么。我尝试使用 aws-sdk-mock 和 sinon 来模拟 aws S3,但我真的不知道如何以及在哪里模拟这个?

这是我的代码:

// documentController

var aws = require('aws-sdk');
aws.config.update({
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    region: 'ap-southeast-1'
});
var s3 = new aws.S3({apiVersion: '2006-03-01'});

function deleteObject(key) {
    s3.deleteObject({
        'Bucket': 'delete-bucket',
        'Key': key,
    }, function(err, data) {
        return
    })
};

create: function(req, res) {
   sails.async.auto(req, {
        getDocumentContent: ['teamPrefDoc', 'getDocument', function (results, cb) {
                var docKey = (
                    results.getDocument && results.getDocument.key
                ) ? results.getDocument.key : '';
                var bucket = 'individual-docs';
                if (!docKey || !bucket) {
                    return res.badRequest("Document doesn't have a key");
                }
                var params = {
                    Bucket: bucket,
                    Key: docKey
                };
                var tempDocStream = fs.createWriteStream(tempFileName + '.doc');
                var s3Stream = s3.getObject(params).createReadStream();
                s3Stream.pipe(tempDocStream).on('close', function() {
                    tempDocStream.close();
                    return cb(null, true);
                }).on('error', function(err) {
                    sails.log(err);
                    return cb(null, false);
                });
            }],
       'savePdfToS3': ['convertToPdfLocally', function (results, cb) {
                if (!results.convertToPdfLocally) {
                    return cb(null, false)
                }
                var s3Key = results.documentDoc.key + '/pdf';
                fs.readFile(tempFileName + '.pdf', (err, pdfBuffer) => {
                    if (err) { return cb(err); }
                    s3.putObject({
                        'Bucket': results.getDocumentContent,
                        'Key': s3Key,
                        'Body': pdfBuffer,
                        'ContentType': 'application/pdf'
                    }, function(err, data) {
                        if (err) { return cb(err); }
                        Documents.update({
                            id: id
                        }, {
                            pdf_key: s3Key
                        }).exec(function(err, updatedDocs) {
                            if (err) {
                                sails.log("Couldn't write pdf url to document", err);
                                return cb(err);
                            }
                            return cb(null, updatedDocs[0]);
                        });
                    })
                });
            }],
   }
}

我有一个运行创建函数的 API,它运行一些数据库查询并将文档保存到 s3。所以,我想测试这个 API,但我不知道如何模拟 s3.getObject 和 s3.putObject。

这是我运行设置和拆卸连接的测试文件

// bootstrap.test.js

var sinon = require('sinon')
var AWSMock = require('aws-sdk-mock')

before(async () => {
     const getObjectStub = AWS.S3.prototype.getObject = sinon.stub();
     var s3 = new Aws.S3();
     AWSMock.mock('S3', 'getObject', function(parmas,callback){
         console.log("Callback received for getObject");
         callback(null,'Success');
     });
     AWSMock.mock('S3', 'deleteObject', function(param,callback){
       callback(null,{'s3deleteMarker': true 
         ,'s3DeleteVersionId': 'VERSION ID' 
         ,'s3DeletedImageSourceUid': 'SOURCE' 
         ,'s3DeletedKey': 'KEY'});
     });

这是我的测试代码:

// document.test.js

describe('document controller', () => {
        it('should upload a doc', done => {
            defaultDocument.resourceId = caseIds[0],
            request(sails.hooks.http.app)
            .post(`${apiVersion}/new/documents?app=test`)
            .set('Authorization', `Bearer ${process.env.ACCESS_TOKEN}`)
            .field(defaultDocument)
            .attach('document0', 'some_pdf.pdf')
            .expect(200)
            .end((err, res)=> {
                if(err) {
                    return done(err)
                }
                console.log(res.body)
                done()
            })
        })
    })

我对单元测试相当陌生,所以我很高兴你能指出我的任何方向:-)

非常感谢!

标签: amazon-s3mocha.jschaisinonaws-sdk-mock

解决方案


关于 aws-sdk-mock 的关键点是“需要在被测试的函数内初始化 AWS 服务,以便模拟 SDK 方法”。

使用您正在使用的字典控制器样式很难知道这将如何工作(模拟工作可能有太多的魔力:

module.exports = {
  login: function (req, res) { ... },
  logout: function (req, res) { ... },
  signup: function (req, res) { ... },
}

Sails 对您的代码结构非常固执己见,我认为您无法创建直接运行您的 api 的集成测试,无论您如何构建您的控制器,而无需大量黑客攻击。

Sails 文档建议将不依赖于请求、响应的代码移动到帮助函数中,例如deleteObject函数。对 getDocumentContent 的内容抽出类似的函数,放在一个单独的模块中。然后你仍然需要在每个辅助函数中实例化对象:

const s3 = new aws.S3();

我会做的是重写我的辅助函数,比如

function deleteObject(s3, key) {
     s3.deleteObject...
}

通过这种方式,您可以传入任何您喜欢的内容并做出断言,以证明对 s3 对象的请求是在不同场景下按预期构建的。

我会编写我的集成测试以走上幸福的道路并写入实际的 s3 存储桶。


推荐阅读