我正在尝试在AWS Firehose对象上模拟putRecord方法但是模拟没有成功。代码最终在firehose对象上调用aws-sdk api,该对象与live aws服务进行通信。以下代码有什么问题?需要改变哪些以避免这种实时服务调用并使模拟生效?
有没有办法发送一个可对象而不仅仅是普通对象,就像下面的回调一样?即在某种程度上使用我在测试代码中定义的callbackFunc之类的东西?
最后我还需要检查模拟是否被调用。我怎么做到这一点?我可以用某种方式使用sinon.stub实现这一点,以便以后我可以验证吗?怎么样?
以下是代码和测试代码部分...修改为此发布的简单形式。
作为文件一部分的代码说samplelogging.js。 ...
require 'singleton'
class Logger
include Singleton
def initialize
@log = File.open("log.txt", "a")
end
def log(msg)
@log.puts(msg)
end
end
Logger.instance.log('message 2')
这是我的测试代码,它是文件的一部分,例如sampleloggingtest.js ...
/*jshint strict:true */
/*jshint node:true */
/*jshint esversion:6 */
/*jshint mocha:true */
"use strict";
var Promise = require('bluebird');
var AWS = require('aws-sdk');
var uuid = require('uuid');
AWS.config.setPromisesDependency(Promise);
var Logger = {
/**
* Get's a AWS Firehose Instance
*/
getFirehoseInstance: function getFirehoseInstance() {
if (!(this.firehose)) {
this.firehose = new AWS.Firehose({apiVersion: "2015-08-04", region: "us-west-2"});
}
return this.firehose;
},
getLogger: function getLogger(options) {
options = options || {};
let self = this;
self.class = options.class;
self.firehose = self.getFirehoseInstance();
return self;
},
logInfo: function logInfo(dataToLog, callback) {
this._log("info", dataToLog)
.then(function (data){
if (callback) {
callback();
}
});
return;
},
/**
* @api: private
*/
_log: function _log(traceLevel, dataToLog) {
return new Promise(function(resolve, reject) {
var params = params || {};
AWS.config.update({ logger: process.stdout });
AWS.config.update({ retries: 3 });
var recordParams = {
type: params.type || 'LogEntry'
};
if (typeof dataToLog === 'string' || dataToLog instanceof String) {
recordParams.data = { message: dataToLog };
} else {
recordParams.data = dataToLog;
}
recordParams.data.id = uuid.v1();
recordParams.data.preciseTimestamp = Math.floor(new Date().getTime()/1000);
recordParams.data.class = this.class;
recordParams.data.traceLevel = traceLevel;
var firehoseRecordParams = {
DeliveryStreamName: "mystreamname", //replace mystreamname with real stream name
Record: {
Data: JSON.stringify(recordParams)+',\n'
}
};
this.firehose.putRecord(firehoseRecordParams, function(err, recordId) {
console.log("debug: recordId returned by putRecord = " + JSON.stringify(recordId));
return resolve(recordId);
});
}.bind(this));
}
};
module.exports = Logger;
答案 0 :(得分:0)
分享我想出的答案,特别是因为另一个人(mmorrisson)也试图这样做。
基本上我将_setFirehoseInstance方法添加到我的logger类中,该类只能从我的测试代码中调用,该代码用我自己的简单模拟类替换firehose实例(在生产代码中称为新的AWS.Firehose())。
在我的测试代码中...... 让firehoseMock = {};
在beforeEach()中创建并设置mock来替换actualfirehose实例并在afterEach()中恢复它。
beforeEach(function (done) {
logger = new Logger({class: "Unit Test"});
firehose = logger.getFirehoseInstance();
consoleMock = sinon.mock(console);
firehoseMock.putRecord = function(params, callback) {
let recordIdObj = {"RecordId": recordIdVal};
callback(null, recordIdObj);
};
logger._setFirehoseInstance(firehoseMock);
sinon.spy(firehoseMock, "putRecord");
done();
});
afterEach(function (done) {
firehoseMock.putRecord.restore();
logger._setFirehoseInstance(firehose);
consoleMock.restore();
done();
});
在我们尝试记录的测试代码中,检查是否调用了firehoseMock.putRecord ...
it("Test AWS firehose API invoked", function (done) {
logger.setMode("production");
logger.setEnvironment("test");
logger.logInfo({ prop1: "value1" }, function(data){
expect(firehoseMock.putRecord.calledOnce).to.equal(true); // should have been called once
expect(data.RecordId).to.equal(recordIdVal); // should have matching recordId
done();
});
});
在生产代码中,logger类中有firehose实例的getter和setter。
/**
* Get's a AWS Firehose Instance
*/
getFirehoseInstance() {
if (!(this.firehose)) {
this.firehose = new AWS.Firehose({apiVersion: Config.apiVersion, region: Config.region});
}
return this.firehose;
}
/**
* Set a AWS Firehose Instance - for TEST purose
*/
_setFirehoseInstance(firehoseInstance) {
if (firehoseInstance) {
this.firehose = firehoseInstance;
}
}
这对我有用。当logger在生产中调用firehose实例方法时,它将转到AWS服务但在单元测试中,当我调用log方法时,它在mock上调用putRecord,因为我已经用mock替换了firehose实例。然后,我可以适当地测试是否调用了mock上的putRecord(使用sinon.spy)。