[rails][rspec]database-cleanerを使ってredisのテストデータを削除する
今更ながら最近ちゃんとredisを使い始めました。
これまでは使ったとしてもキャッシュやsession_storeにしか使っていなかったのですが、setやsorted setを使うと色々できて奥が深いですね。
railsからredisのデータを扱う際には、 redis-objectsを使うと便利でした。
redis-objectsの設定方法に関しては、Gemfileにredis-objectsを追加し、(namespaceを設定したかったのでredis-namespaceも使っています)
# Gemfile
gem 'redis-objects'
gem 'redis-namespace'
rails_configの設定にredisの接続情報を記述します。
# config/settings.yml
redis:
host: localhost
port: 6379
object_db: 1
redisの接続情報をinitializerに記述。
# config/initializers/redis.rb
namespace = [Rails.application.class.parent_name, Rails.env, 'object'].join(':').downcase
Redis.current = Redis::Namespace.new(namespace, :redis => Redis.new(:host => Settings.redis.host, :port => Settings.redis.port, :db => Settings.redis.object_db))
namespaceを指定しつつ、dbも分けて管理することにしています。(デフォルトのdbは0番)
あとはmodelでRedis::Objectsをincludeすると、redis-objectsが使用可能になります。
詳しい使い方に関しては redis-objectsのgithubに記載されているので参照ください。
今回つまづいたのはredis-objectsを使ったモデルのテストをRSpecで書こうとした際に、テストデータをどうやって削除するかということでした。
ActiveRecordの場合は database_cleanerを使ってテスト実行の度にデータをリセットするようにしていたので、redsでも同様のことができないか調べたところ、database_cleanerはredisもサポートしてくれていました。
ただ、after(:each)でDatabaseCleaner.cleanを実行するだけだとredsのデータが残ったままになってしまったので、 DatabaseCleaner[:redis].clean
を実行するようにしました。
また、デフォルトだとlocalhost:6379のdb0に対してflushdbが実行されるので、ローカル開発や他のプロジェクトでdb0を使用しているとテストを実行すると他のデータも消されてしまいます。
これを防ぐためにはstrategy設定の際に、redisのkeysコマンドに指定する値を設定することで特定のキーのみ削除ということができるようです。
# spec/support/database_cleaner.rb
DatabaseCleaner.strategy = :truncation, {:only => %w[*test* ]} # *test*に該当するキーのみ削除
もしくはテスト用にdbを分けてしまうのが手っ取り早くできそうです。
今回はテスト用にdbを分ける方針で進めることにしました。
例としてdb2番をテストデータ専用dbとします。
最終的なdatabase_cleanerの設定は以下のようになりました。
# spec/support/database_cleaner.rb
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner[:redis].db = 'redis://localhost:6379/2' # デフォルト設定(0番をテストdbにする)の場合はこの行がなくてもok
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
DatabaseCleaner[:redis].clean # flushdbを実行
end
end
これでdatabase_cleanerはテスト実行の度にdb2番にflushdbを実行してくれるようになります。
ただし、このままだとredis-objectsはdb1にデータを見に行くので、テスト環境の場合のみdb2を見に行くようにinitializerを書き換えます。
# config/initializers/redis.rb
namespace = [Rails.application.class.parent_name, Rails.env, 'object'].join(':').downcase
Redis.current = Redis::Namespace.new(namespace, :redis => Redis.new(:host => Settings.redis.host, :port => Settings.redis.port, :db => Rails.env.test? ? 2 : Settings.redis.object_db))
これでテスト実行時にredisのデータを削除できるようになりました。
手探りで状態で色々調べながら対応したので、もっと良い方法あれば教えていただけると助かります。