如何从外部范围调用一个方法到被testing的函数?

我有一个使用node_redis库创build的Redis客户端( https://github.com/NodeRedis/node_redis ):

var client = require('redis').createClient(6379, 'localhost'); 

我有一个方法,我想testing其目的是为Redis设置和发布一个值,所以我想testing,以确保setpublish方法调用或不按照我的期望调用。 棘手的是我希望这个testing不需要启动一个Redis服务器的实例,所以我不能创build客户端,因为如果它不能检测到Redis,它会抛出错误。 因此,我需要存根createClient()方法。

示例方法:

 // require('redis').createClient(port, ip) is called once and the 'client' object is used globally in my module. module.exports.updateRedis = function (key, oldVal, newVal) { if (oldVal != newVal) { client.set(key, newVal); client.publish(key + "/notify", newVal); } }; 

我已经尝试了几种testing设置和发布的方法是否使用期望的键和值来调用,但是不成功。 如果我试图窥探这些方法,我可以通过运行debugging器来告诉我的方法正在调用,但是对于我来说,调用一次被标记为true。 如果我存根createClient方法返回假客户端,如:

 { set: function () { return 'OK'; }, publish: function () { return 1; } } 

被测方法似乎没有使用假客户端。

现在,我的testing看起来像这样:

 var key, newVal, oldVal, client, redis; before(function () { key = 'key'; newVal = 'value'; oldVal = 'different-value'; client = { set: function () { return 'OK'; }, publish: function () { return 1; } } redis = require('redis'); sinon.stub(redis, 'createClient').returns(client); sinon.spy(client, 'set'); sinon.spy(client, 'publish'); }); after(function () { redis.createClient.restore(); }); it('sets and publishes the new value in Redis', function (done) { myModule.updateRedis(key, oldVal, newVal); expect(client.set.calledOnce).to.equal(true); expect(client.publish.calledOnce).to.equal(true); done(); }); 

上面的代码给了我一个断言错误(我使用柴)

AssertionError: expected false to equal true

我也在控制台日志中得到这个错误,这表明客户端在方法实际运行时没有被截断。

Error connecting to redis [Error: Ready check failed: Redis connection gone from end event.]

UPDATE

我已经尝试在我的testing套件的最外层描述的块中使用相同的结果来createClient方法(使用before函数,以便它在我的testing之前运行) – 看起来它不会返回假客户端testing实际上运行我的function。

我也曾试图把我的间谍放在顶层describe before ,但没有成功。

我注意到,当我杀掉Redis服务器时,我收到了来自Redis的连接错误消息,尽pipe这是唯一一个触及使用Redis客户端的代码的testing。 我知道这是因为我创build客户端,当这个NodeJS服务器启动,摩卡将执行testing时创build服务器应用程序的实例。 我现在认为,这是不正确的原因是因为它不仅仅是一个需求,但createClient()函数被称为在应用程序启动,而不是当我打电话给我的function正在testing。 我觉得仍然应该有一个方法来存根这个依赖,即使它是全球性的,被testing函数之前被调用的函数被调用

其他可能有用的信息:我正在使用Gulp任务运行程序 – 但我不明白这将如何影响testing运行。

Solutions Collecting From Web of "如何从外部范围调用一个方法到被testing的函数?"

我最终使用fakeredishttps://github.com/hdachev/fakeredis )在我的testing套件中创buildapp之前将Redis客户端fakeredis如下所示:

 var redis = require('fakeredis'), konfig = require('konfig'), redisClient = redis.createClient(konfig.redis.port, konfig.redis.host); sinon.stub(require('redis'), 'createClient').returns(redisClient); var app = require('../../app.js'), //... and so on 

然后我可以正常的方式使用sinon.spy:

 describe('some case I want to test' function () { before(function () { //... sinon.spy(redisClient, 'set'); }); after(function () { redisClient.set.restore(); }); it('should behave some way', function () { expect(redisClient.set.called).to.equal(true); }); }); 

也可以在客户端上模拟和存储事情,比使用redisErrorClient提供的在callback中testingRediserror handling更好。

很明显,我不得不求助于Redis的模拟库来完成这个工作,因为只要它在外部范围内被调用到被testing的函数中,Sinon就不能删除redisClient()方法。 这是有道理的,但这是一个讨厌的限制。