2015-09-25 6 views
1

Учитывая что-то вроде:rspec: Как протестировать redis # код подписки?

class MyClass 
    def subscribe 
    $redis.subscribe('channel') do |on| 
     on.message do |channel, msg| 
     Something.create(msg) 
     end 
    end 
    end 
end 

Как я могу проверить, что когда MyClass выполняет subscribe, он будет работать Something.create для каждого сообщения, которое он получает на канале?

+0

Почему вы используете '$ redis' как глобальные переменные? –

+0

Теоретически говоря, у вас есть два способа сделать это: 1- Mocking Redis object 2- Проверить, был ли msg опубликован для канала. – moeabdol

+0

Alexey: чтобы было проще понять код, в моем реальном коде это @store, но тогда мне нужно было бы поместить код init в образец, и я хотел бы использовать голой случай использования кости. – Alain

ответ

2

Этот код у вас есть, это не очень проверяемо. Прежде всего, полностью избавиться от этой глобальной переменной $redis. Вместо этого, примите экземпляр redis в конструкторе.

class MyClass 
    attr_reader :redis 

    def initialize(redis) 
    @redis = redis 
    end 

    def subscribe 
    redis.subscribe('channel') do |on| 
     on.message do |channel, msg| 
     Something.create(msg) 
     end 
    end 
    end 
end 

Затем в тестах вы можете сделать манекен Redis, что вы можете полностью контролировать, но который соответствует API, который вы используете. Что-то вдоль этих линий:

class DummyRedis 
    def subscribe(&block) 
    @block = block 
    end 

    def trigger_on 
    @block.call make_on_message 
    end 
end 


fake_redis = DummyRedis.new 

expect { 
    mc = MyClass.new(fake_redis) 
    mc.subscribe 
    fake_redis.trigger_on 
}.to change{Something.count}.from(0).to(1) 

Этот прохладный прием называется Dependency Injection (или, как некоторые люди выразились, «передача параметров в конструкторах»).

+0

Я знаю все о DI, я делал это много, но с rspec 'allow' я считаю, что я использую его только в качестве последнего средства (что может иметь место здесь), потому что я не люблю добавлять сложность, когда это Онил оправдан, чтобы сделать тесты проще. – Alain

+0

А, ладно. Я скоро удалю свой ответ :) –

+0

Ну, у DI есть и другие преимущества, помимо облегчения тестирования. Самое главное, уменьшение сцепления. –

0

Хотя этот подход не использует фактические тесты, я бы сделал следующее и проверил журналы.

class MyClass 
    def subscribe 
    $redis.subscribe('channel') do |on| 
     on.message do |channel, msg| 
     event = Something.create(msg) 
     p event.persisted? ? "success" : "fail" 
     p event 
     end 
    end 
    end 
end 
0

Ну, это может быть столь же легко, как

describe MyClass do 
    it 'should create something' do 
    expect(Something).to receive(:create) 
    subject.subscribe 

    subject.trigger_message # you should trigger a message somehow 
    end 
end 
Смежные вопросы