2012-10-27 61 views
5

我无法得到我的头部轮廓如何使用sinon来模拟我测试的模块所需的postgres调用,或者如果它是平坦的可能。在Node.js中使用Sinon.js进行单元测试的嘲讽Postgres

我不想测试postgres模块本身,只是我的对象,以确保它按预期工作,并且它正在调用它应该在这种情况下调用。

我想问题是节点的需求设置,因为我的模块需要postgres模块来打数据库,但在这里我不想运行集成测试我只是想确保我的代码是单独工作,并不在乎数据库在做什么,我会把它留给我的集成测试。

我见过一些人设置他们的函数有一个可选参数来发送模拟/存根/假到函数,测试其存在,如果它在那里使用它在所需的模块,但似乎像一种气味给我(我在节点新,所以也许这不是)。

我宁愿嘲笑这一点,而不是尝试劫持需求,如果这是可能的。

一些代码(请注意,这不是真正的代码,就像我跟TDD运行, 功能并不做任何事情真的,函数名是真实的)

测试设置

describe('#execute', function() { 
it('should return data rows when executing a select', function(){ 
//Not sure what to do here 
}); 
}); 

示例函数

PostgresqlProvider.prototype.execute = function (query, cb) { 
var self = this; 

if (self.connection === "") 
    cb(new Error('Connection can not be empty, set Connection using Init function')); 

if (query === null) 
    cb(new Error('Invalid Query Object - Query Object is Null')) 

if (!query.buildCommand) 
    cb(new Error("Invalid Query Object")); 

//Valid connection and query 
}; 

看起来有点像这样包装postgres模块有趣,但有一些设计,因为这个应用程序将有几个“供应商”,我想为他们公开相同的API,所以我可以交替使用它们。

UPDATE

我决定,我的测试太复杂了,因为我想看看如果连接调用了,然后返回数据,其中冶炼到我,所以我剥夺回来,并把它分为两个测试:

模拟测试

it('should call pg.connect when a valid Query object is parsed', function(){ 
     var mockPg = sinon.mock(pg); 
     mockPg.expects('connect').once;    

     Provider.init('ConnectionString'); 
     Provider.execute(stubQueryWithBuildFunc, null, mockPg); 

     mockPg.verify(); 
    }); 

这工作(我认为)因为没有它失败的Postgres连接器代码,它过时了s(Boom :))

问题现在是第二种方法,我将使用一个存根(可能是间谍),当它应该失败时通过100%,所以我会在早上选择它。

更新2

我不开心与测试100%,主要是因为我不是劫持client.query方法,它是访问数据库的一个,只是我的执行方法,并迫使它沿着一条路径走,但它允许我看到结果并断言它会测试行为,但对任何建议的改进都是开放的。

我正在使用间谍来捕获该方法,并返回null和包含行的人造对象,就像该方法将传回一样,此测试将随着添加更多查询行为而发生变化,但它会让我超过我的障碍。

it('should return data rows when a valid Query object is parsed', function(){ 

     var fauxRows = [ 
      {'id': 1000, 'name':'Some Company A'}, 
      {'id': 1001, 'name':'Some Company B'} 
     ]; 

     var stubPg = sinon.stub(Provider, 'execute').callsArgWith(1, null, fauxRows); 

     Provider.init('ConnectionString'); 
     Provider.execute(stubQueryWithBuildFunc, function(err, rows){ 
      rows.should.have.length(2); 
     }, stubPg); 

     stubPg.called.should.equal.true; 
     stubPg.restore(); 
    }); 
+0

它似乎需要一个有效的连接第一 - 这意味着一个运行的postgres实例来响应连接,以允许单元测试......是吗? – Reinsbrain

+0

说实话,我们改变了道,不再使用postgres,所以这可能有点关闭,但是如果你正确地嘲笑你不应该需要一个正在运行的实例,存根/间谍应该作为连接,你应该能够在此基础上测试您的代码。 – Modika

+0

我已经与brianc谁是主要贡献者联系了,他提到pg即将到来会发生重大变化,这将使单元测试变得更容易......我将在未来访问者的答案中详细说明这个问题... – Reinsbrain

回答

1

我非常明确地取代我的依赖关系。这可能不是最好的解决方案,但我看到的所有其他解决方案都不是那么好。

inject: function (_mock) { 
    if (_mock) { real = _mock; } 
} 

您将此代码添加到被测模块中。在我的测试中,我调用注入方法并替换真实的对象。我之所以没有100%喜欢它,是因为你必须为测试添加额外的代码。

另一种解决方法是将模块文件读取为字符串,并使用vm来手动加载文件。当我调查这个时,我发现它有点复杂,所以我只用了注入函数。尽管如此,这可能是值得研究的。你可以找到更多的信息here

+0

感谢您的答复,有趣的方法,但我试图保持我的模块尽可能干净,如果我可以,我已经找到了一项工作,我已经更新了问题,带领我第二个考试头脑的另一个问题。 – Modika