2015-11-19 120 views
0

我是新手到Node.js,我正在为HBase编写DAO层,它将包装节俭并为其他层提供清晰的接口。我正在尝试使用sinon.jsmocha编写单元测试,但不确定如何确保模拟Thrift连接类及其事件处理程序的一个事件。如何使用sinon.js来模拟事件处理程序方法?

我的DAO代码如下:

var thrift = require('thrift'); 
var libDirRelativePath = "../../../lib"; 
var hbaseThriftDirPath = libDirRelativePath + "/hbase-gen-nodejs"; 
var hbase = require(hbaseThriftDirPath + '/THBaseService'); 
var hbaseTypes = require(hbaseThriftDirPath + '/hbase_types'); 

var thritfPrimaryServerAddress = 'nn2'; 
var thritfBackupServerAddress = 'backup-nn2'; 
var thriftServerPort = 9090; 

exports.putRows = function(tableName, putObjectArray, callback) { 
    var primaryClusterConnection = thrift.createConnection(thritfPrimaryServerAddress, thriftServerPort, { 
     transport: thrift.TBufferedTransport, 
     protocol : thrift.TBinaryProtocol 
    }); 

    console.log('DEBUG : connection object created.'); 

    var client = thrift.createClient(hbase, primaryClusterConnection); 
    console.log('DEBUG : client object created.'); 

    primaryClusterConnection.on('connect', onConnectOfPutRows); 

    primaryClusterConnection.on('connect', function() { 
     console.log('Connected to HBase thrift server at ' + thritfPrimaryServerAddress + ":" + thriftServerPort); 
     client.putMultiple(tableName, putObjectArray, callback); 
     connection.close(); 
    }); 

    primaryClusterConnection.on('error', function() { 
     console.log('Error occurred in HBase thirft server connection.'); 
    }); 
} 

对于上面的代码中,我只是想创建存根primaryClusterConnection和我所管理,但问题是primaryClusterConnection存根没有任何想法有关connectclient对象事件及其处理程序,所以console.log('Connected to HBase thrift server at '...行永远不会执行。我也想测试那部分代码。任何人都可以帮助我写出适当的存根/嘲笑这个问题?

我的测试代码如下:

var hbaseDao = require('../../../src/dao/hbase/HBaseDao.js'); 
var libDirRelativePath = "../../../lib"; 
var hbaseThriftDirPath = libDirRelativePath + "/hbase-gen-nodejs"; 
var hbase = require(hbaseThriftDirPath + '/THBaseService'); 

var chai = require('chai'); 
var should = chai.should(); 
var expect = chai.expect; 
var sinon = require('sinon'); 

describe("HBaseDao", function() { 
    describe(".putRows()", function() { 

     it("Should execute callback after inserting objects in HBase.", function(done) { 
      var commonStub = sinon.stub(); 
      var connection = { 
       close : function() { 
        console.log('connection closed.'); 
       } 
      }; 
      commonStub.withArgs('nn2', 9090).returns(connection); 
      var client = {}; 
      commonStub.withArgs(hbase, connection).returns(client); 
      var tableName = 'DUMMY_READINGS_TABLE'; 
      var callBackMethod = function() { 
       console.log('dummy callback function.'); 
      }; 
      commonStub.withArgs(tableName, [], callBackMethod).returns(0); 

      hbaseDao.putRows(tableName, [], callBackMethod); 
      expect(hbaseDaoSpy.callCount).to.equal(1); 
      done(); 
     }); 

回答

1

让我们通过简化问题有点开始。

it.only("Should execute callback after inserting objects in HBase.", function(done) { 

    var events = require('events'); 
    var hbaseDao = new events.EventEmitter(); 
     hbaseDao.putRows = function() { 
      console.log('putting rows'); 
      this.emit('notify'); 
     }; 
     hbaseDao.on('notify', function(){ 
      console.log('notify event fired'); 
      done(); //here's where you call the callback to assert that the event has fired 
     }); 

    sinon.spy(hbaseDao, 'putRows'); 

    var commonStub = sinon.stub(); 
    var tableName = 'DUMMY_READINGS_TABLE'; 
    var client = {}; 
    var connection = { 
     close : function() { 
      console.log('connection closed.'); 
     } 
    }; 
    var callBackMethod = function() { 
     console.log('dummy callback function.'); 
    }; 

    commonStub.withArgs('nn2', 9090).returns(connection); 
    commonStub.withArgs({}, connection).returns(client); 
    commonStub.withArgs(tableName, [], callBackMethod).returns(0); 

    hbaseDao.putRows(tableName, [], callBackMethod); 

    //assertions 
    assert(hbaseDao.putRows.calledOnce); 

}); 

上述测试将只是工作,因为它是从一个简单的事件发射器创建一个新的“hbaseDao”,有方法和通知事件蓄势待发。

因为我们正在做一个异步测试,我们需要在规范中完成回调。注意,这只会在事件发生时触发“完成”。因此,除非事件触发,否则测试不会通过。另外请注意,我们正在专门研究hbaseDao'putRows',并且我们断言它只会被调用一次,这是确保测试正常工作的另一种方法。现在考虑这个例子,并将其应用于您的原始问题。

我想你几乎得到它,但是你需要把你做回调回调存根像这样:

var callBackMethod = function() { 
    console.log('dummy callback function.'); 
    done(); 
}; 

这样,当你primaryClusterConnection.on('connect')事件被触发时,提供的回调将执行DONE并完成测试。这就是说,你应该保持primaryClusterConnection完整,并让hbaseDao的实现细节在你的测试中不被考虑。

你提到:

primaryClusterConnection没有任何想法有关连接

但是,这不可能是正确的,因为你正在创建测试新的连接,有您的实施中没有任何内容告诉我您已更改连接的事件处理程序。

所以我认为最后,你错过了测试的重点,这只是should execute callback...,你正在扼杀你甚至不需要的东西。

尝试这样:

//use it.only to make sure there's no other tests running 
it.only("Should execute callback after inserting objects in HBase.", function(done) { 

    //get the class 
    var hbaseDao = require('../../../src/dao/hbase/HBaseDao.js'); 

    //spy on the method 
    sinon.spy(hbaseDao, 'putRows'); 

    //create a table name 
    var tableName = 'DUMMY_READINGS_TABLE'; 

    //create callback method with done. 
    var callBackMethod = function() { 
     console.log('dummy callback function.'); 
     done(); 
    }; 

    //run the function under test 
    hbaseDao.putRows(tableName, [], callBackMethod); 

    //assert called once 
    assert(hbaseDao.putRows.calledOnce); 

}); 
相关问题