Stubbing взаимодействия Redis в javascript с использованием Sinon

Я работаю в node.js. Мое приложение взаимодействует с Redis через модуль node_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, или это возможно?

Ответ 1

Что вы можете сделать, это использовать что-то вроде Proxyquire или Rewire. Я буду использовать rewire для примера.

Ваш фрагмент кода, который вы хотите заглушить:

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

Затем в вашем тесте вы можете использовать rewire:

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, и вы можете проверить со шпионом, если функция была вызвана.

Ответ 2

Вы также можете использовать что-то вроде redis-mock, который заменяет node_redis который работает в памяти.

Используйте rewire (или Jest-модуль Jest или что-то еще), чтобы загрузить фиктивный клиент в ваши тесты вместо реального клиента и запустить все ваши тесты для версии в памяти.

Ответ 3

Другой способ - сделать в вашем классе статическую функцию 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);

Ответ 4

Изначально это показалось мне тривиальным, но я столкнулся с множеством предостережений, особенно потому, что для тестирования я использовал 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 или proxyquire с jest, что вам нужна библиотека, такая как rewiremock, чтобы высмеивать эту зависимость.

Пример REPL