使用Sinon在javascript中存储Redis交互

时间:2014-07-24 14:56:41

标签: javascript node.js redis mocha sinon

我在node.js工作。我的应用程序通过node_redis模块与Redis交互。我使用mocha和sinon自动测试我的应用程序。我的应用程序看起来像这样:

...snip
var redisClient = redis.createClient(redisPort, redisHost);
var someValue = redisClient.get("someKey");
return someValue;
....

我想将调用存根到redisClient.get()。要做到这一点,我还需要将调用存根到redis.createClient() - 我认为......这是我的测试代码:

...
var redis = require("redis");
var redisClient;
...
sinon.stub(redisClient, 'get').returns("someValue");
sinon.stub(redis, "createClient").returns(redisClient);
...
assert.equal(redis_client_underTest.call_to_redis(), "someValue");
...

测试失败,AssertionError: false == "someValue"

如何删除redisClient,或者这甚至可能?

6 个答案:

答案 0 :(得分:8)

您可以使用ProxyquireRewire之类的内容。我将使用重新连线作为例子。

您想要存根的代码片段:

var redisClient = redis.createClient(redisPort, redisHost);
var someValue = redisClient.get("someKey");
return someValue;

然后在你的测试中你可以使用重新连接:

var Rewire = require('rewire');

var myModule = Rewire("../your/module/to/test.js");

var redisMock = {
    get: sinon.spy(function(something){
             return "someValue";
         });
};

myModule.__set__('redisClient', redisMock);

通过这种方式,您可以更换redisClient,如果调用该函数,您可以检查间谍。

答案 1 :(得分:0)

您还可以使用类似redis-mock的名称,它代替了运行在内存中的node_redis

使用rewire(或Jest模块模拟或任何其他方式)将模拟客户端(而不是真实客户端)加载到测试中,并针对内存版本运行所有测试。

答案 2 :(得分:0)

另一种方法是在您的类静态函数getRedis中进行模拟。例如:

let redis = {
   createClient: function() {},
};
let connection = {
   saddAsync: function() {},
   spopAsync: function() {},
};
let saddStub = sinon.stub(connection, 'saddAsync');
sinon.stub(redis, 'createClient').returns(connection);
sinon.stub(Redis, 'getRedis').returns(redis);

expect(saddStub).to.be.calledOnce;

您的类内部连接函数如下:

this.connection = YourClass.getRedis().createClient(port, host, optional);

答案 3 :(得分:0)

几个关键点是:

  • 在加载主模块之前先存根redisClient。
  • 为redisClient添加CRUD方法。

下面是我的主要模块:

/* Main module */
const redis = require('redis');
const redisClient = redis.createClient();

function value(){
  return redisClient.get('someKey');
}

module.exports = {value: value}

下面是我的测试脚本:

/* Test */
var sinon = require('sinon');
var redis = require('redis');

// stub redis.createClient

var redisClient = {
    'get': () => "someValue"
}

var redisGetSpy = sinon.spy(redisClient, "get");
var redisClientStub = sinon.stub(redis,
                                 "createClient").callsFake(() => redisClient);

// require main module
var main = require('./main.js');

console.log(main.value(),
            redisClientStub.called,
            redisGetSpy.called, 
            redisGetSpy.callCount);

答案 4 :(得分:0)

const sinon = require('sinon');
const redis = require('redis');
const { mapValues, isObject, isUndefined, noop, isFunction } = require('lodash');

let redisStub;
let redisStore = {};

const removeKeyWhenExpired = (db, key, expirationSec) => {
    setTimeout(() => {
        redisStore[db || 0][key] = undefined;
    }, expirationSec * 1000);
};

sinon.stub(redis, 'createClient').callsFake(() => ({
    on: () => { },
    select: (db) => {
        this.db = db;
        redisStore[db] = {};
    },
    get: (key, callback) => callback(null, redisStore[this.db || 0][key]),
    set: (key, value, ...args) => {
        redisStore[this.db || 0][key] = isObject(value) ? JSON.stringify(value) : value;
        if (args[0] === 'EX') {
            removeKeyWhenExpired(this.db, key, args[1]);
        }
        const callback = args[args.length - 1] || noop;
        if (isFunction(callback)) {
            callback(null, true);
        }
    },
    del: (key, callback = noop) => {
        if (!isUndefined(redisStore[this.db || 0][key])) {
            redisStore[this.db || 0][key] = undefined;
            return callback(null, 1);
        }
        return callback(null, 0);
    },
    expireat: (key, exp, callback = noop) => {
        removeKeyWhenExpired(this.db, key, exp - (new Date().getTime() / 1000));
        return callback(null);
    },
}));

答案 5 :(得分:-1)

起初,这对我来说似乎是微不足道的,但是我面临许多警告,特别是因为我使用jest进行测试,但不支持proxyquire。我的目标是模拟redis的请求依赖关系,所以这是我的实现方式:

// The objective is to mock this dependency
const redis = require('redis');

const redisClient = redis.createClient();
redis.set('key','value');

rewiremock模拟依赖项:

const rewiremock = require('rewiremock/node');

const app = rewiremock.proxy('./app', {
  redis: {
    createClient() { 
      console.log('mocking createClient');
    },
    set() {
      console.log('mocking set');
    }
  },
});

要注意的是,您不能使用rewire或将proxyquirejest一起使用,需要像rewiremock这样的库来模拟这种依赖关系。

REPL example