Given something like:
class MyClass
def subscribe
$redis.subscribe('channel') do |on|
on.message do |channel, msg|
Something.create(msg)
end
end
end
end
How can I test that when MyClass
executes subscribe
, it will run Something.create
for each message it receives on the channel?
This code you have, it's not very testable. First of all, absolutely get rid of this global $redis
variable. Instead, accept an instance of redis in the constructor.
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
Then in tests you can make a dummy redis that you can totally control but which conforms to the api you're using. Something along these lines:
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)
This cool technique is called Dependency Injection (or, as some people put it, "passing parameters to constructors").
Although this approach is not using actual tests, i would do the following and check the logs.
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
Well, it could be as easy as
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