Reputation: 13404
I have a model class that caches data in redis. The first time I call a method on the model, it computes a JSON/Hash value and stores it in Redis. Under certain circumstances I 'flush' that data and it gets recomputed on the next call.
Here's the code snippet similar to the one I use to store the data in Redis:
def cache_data
self.data_values = data_to_cache
REDIS.set(redis_key,ActiveSupport::JSON.encode(self.data_values))
REDIS.get(redis_key)
end
def data_to_cache
# generate a hash of values to return
end
How should I unit test this code? I use RSpec and Capybara. I also use Cucumber and Capabara for integration testing if that helps.
Upvotes: 23
Views: 22538
Reputation: 1624
Both the answers are outdated in May 2022. Following is the updated version with a sample test.
add this to Gemfile
gem 'mock_redis'
Install the mock_redis
gem using
bundle install
In your spec_helper.rb
or rails_helper.rb
add this
require 'mock_redis'
RSpec.configure do |config|
'''
Creating a stub/mock Redis for running the tests without requiring an actual Redis server. This will store the Redis data in memory instead of the Redis server.
'''
config.before(:each) do
mock_redis = MockRedis.new
allow(Redis).to receive(:new).and_return(mock_redis)
end
end
This would make sure to mock Redis for all your test.
Let's say you have a module (module_in_my_app.rb
) that uses Redis like so
module ModuleInMyApp
extend self
@@redis = Redis.new(url: "redis://#{ENV["REDIS_URL"]}")
def get_or_create_my_key(keys, default_value)
return @@redis.set(key, value)
end
def get_my_key(key)
return @@redis.get(key)
end
end
You can use it like so in your spec (module_in_my_app_spec.rb
)
describe "test my redis module" do
it "should set the key" do
ModuleInMyApp.set_my_key("US", "United States of America")
redis_var = class_variable_get(:@@redis)
expect(redis_var.get("US")).to eq("United States of America")
end
it "should get the key" do
mock_redis = Redis.new
mock_redis.set("CA", "Canada")
ModuleInMyApp.class_variable_set(:@@redis, mock_redis)
actual_result = ModuleInMyApp.get_my_key("CA")
expect(actual_result).to eq("Canada")
end
end
Upvotes: 8
Reputation: 4117
First of all add the below code in the spec_helper.rb so you'll be sure that the tests will run on any machine even if the redis server is not installed (make sure to add to your gemfile mock_redis under test scopes:
redis_instance = MockRedis.new
Redis.stub(:new).returns(redis_instance)
Redis::Store.stub(:new).returns(redis_instance)
After that I would test:
Upvotes: 23
Reputation: 877
I like to have redis running while the tests are running. Redis, unlike e.g. postgres, is extremely fast and doesn't slow down test run time noticeably.
Just make sure you call REDIS.flush
in a before(:each)
block, or the corresponding cucumber hook.
You can test data_to_cache
independently of redis, but unless you can fully trust the redis driver you're using and the contract it provides, it's safer to actually test cache_data
(and the corresponding cache fetch method) live. That also allows you to switch to a different redis driver (or to a different fast KV store) without a wholesale rewrite of your tests.
Upvotes: 25