编程语言
首页 > 编程语言> > javascript – 如何将从外部作用域调用的方法存根到被测函数?

javascript – 如何将从外部作用域调用的方法存根到被测函数?

作者:互联网

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

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

我有一个我想测试的方法,其目的是设置和发布Redis的值,所以我想测试以确保根据我的期望调用或不调用set和publish方法.棘手的是我希望这个测试能够在不需要启动Redis服务器实例的情况下工作,因此我不能只创建客户端,因为如果无法检测到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);
  }
};

我已经尝试了几种方法来测试是否使用预期的键和值调用set和publish,但是没有成功.如果我试图窥探这些方法,我可以告诉我的方法是通过运行调试器来调用的,但是对于我来说,callOnce并没有被标记为真.如果我将createClient方法存根以返回假客户端,例如:

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

测试中的方法似乎没有使用假客户端.

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

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();
});

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

AssertionError:期望false等于true

我也在控制台日志中收到此错误,这表示当方法实际运行时客户端没有被截断.

连接到redis时出错[错误:就绪检查失败:Redis连接从结束事件中消失.]

UPDATE

我已经尝试在我的测试套件的最外层描述块中尝试删除createClient方法(使用before函数以便它在我的测试之前运行)具有相同的结果 – 它似乎不会返回假客户端时测试实际上运行我的功能.

我也试过把我的间谍放在顶级描述之前无济于事.

我注意到当我杀死我的Redis服务器时,我从Redis收到连接错误消息,即使这是唯一一个触及任何使用Redis客户端的代码的测试(此刻).我知道这是因为我在这个NodeJS服务器启动时创建客户端,Mocha将在执行测试时创建服务器应用程序的实例.我现在想的是,这不是正确的原因是因为它不仅仅是一个需求,而是在app启动时调用createClient()函数,而不是在我调用我正在测试的函数时.我觉得仍然应该有一种方法来存根这种依赖,即使它是全局的,并且在我的测试函数之前调用被存根的函数.

其他可能有用的信息:我正在使用Gulp任务运行器 – 但我不知道这应该如何影响测试的运行方式.

解决方法:

在我的测试套件中创建应用程序之前,我最终使用fakeredis(https://github.com/hdachev/fakeredis)来删除Redis客户端,如下所示:

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更好地测试回调中的Redis错误处理.

显而易见的是,我不得不求助于Redis的模拟库来执行此操作,因为只要在外部作用域中调用正在测试的函数,Sinon就不能存根redisClient()方法.这是有道理的,但这是一个恼人的限制.

标签:javascript,node-js,mocha,sinon,stubbing
来源: https://codeday.me/bug/20190706/1398335.html