如何从外部范围调用一个方法到被testing的函数?
我有一个使用node_redis库创build的Redis客户端( https://github.com/NodeRedis/node_redis ):
var client = require('redis').createClient(6379, 'localhost');
我有一个方法,我想testing其目的是为Redis设置和发布一个值,所以我想testing,以确保set
和publish
方法调用或不按照我的期望调用。 棘手的是我希望这个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运行。
我最终使用fakeredis
( https://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()方法。 这是有道理的,但这是一个讨厌的限制。