最近やってるRailsプロジェクトのテスト方法

Railsエンジニアになってから1年半くらいが経ち、社内のRailsのプロジェクトを全部で5つくらい触って、今やってるAbilie*1でようやく人並みにテストを書いてる気がしてきたので、現時点でやってるテストの方法をまとめておく。

テストのルール的なの

rspecでは必ずモデルのテストは書くようにしてる。ヘルパーも大体書いてるけど、コントローラやルーティングのテストはあまり書いてない。
というのも、コントローラーのコードを極力短くしてモデルを太らせているのでコントローラのテストはあんまり意味が無い気がしていて、その代わりにCapybaraでテストを書いておけば十分なんじゃないかなと思ってきたから。Capybaraは書いてるので、そういう意味では書いてるとも言える。
社内の管理者だけが使える管理画面も作ってるけど、そっちはテストあんまり書いてない。ここは動かなくなっても一般ユーザーには影響が無いので、動かなくなったのを気づいてから直せばいいかなーという感じ。

テストの実行


GuardSpork使Growl
guard/guard · GitHub
guard/guard-spork · GitHub

Guard
SporkRailsrspec
GrowlMac使 # 
Guardguard
Guardfile
guard 'rspec', :version => 2, :cli => "--drb", :all_after_pass => false, :all_on_start => false do

guardEnter

fixture_replacement

factory_girlで特に困ってもないので相変わらずfactory_girlを使ってる。
thoughtbot/factory_girl · GitHub

modelを作成したときにfactory_girlのファイルも生成するようにconfig/application.rbに以下のように書いてる

config.generators do |g|
  g.test_framework :rspec, :fixture => true, :fixture_replacement => :factory_girl
  g.fixture_replacement :factory_girl, :dir => 'spec/factories'
end 

あとSporkを実行してると、factory_girlのファイルに変更があっても更新してくれないので、spec_helper.rbに以下のように書いてる。

Spork.each_run do
  FactoryGirl.reload
  Deadend::Application.reload_routes!
end

カバレッジ


cover_me使simple-cov使
colszowka/simplecov · GitHub

HTMLrcovJenkins使
SporkSpork使
rake specCIrcovspec_helper.rb
unless Spork.using_spork?
  require 'simplecov'
  if ENV["JENKINS"] == 'on'
    require 'simplecov-rcov'
    SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
  end

  SimpleCov.start 'rails' do
    add_filter "/spec/"
  end
end

Redis


resque使Redis使
RSpec and Resque · defunkt/resque Wiki · GitHub
resqueWikiredisconfredis
JenkinsTempFile使
REDIS_PID = "#{Rails.root}/tmp/pids/redis-test.pid"
REDIS_CACHE_PATH = "#{Rails.root}/tmp/cache/"

config.before(:suite) do
  redis_options = {
    "daemonize"     => 'yes',
    "pidfile"       => REDIS_PID,
    "port"          => 9736,
    "timeout"       => 300,
    "save 900"      => 1,
    "save 300"      => 1,
    "save 60"       => 10000,
    "dbfilename"    => "dump.rdb",
    "dir"           => REDIS_CACHE_PATH,
    "loglevel"      => "debug",
    "logfile"       => "stdout",
    "databases"     => 16
  }.map { |k, v| "#{k} #{v}" }

  if ENV["JENKINS"] == 'on'
    require 'tempfile'
    temp = Tempfile::new("redis_temp.conf", REDIS_CACHE_PATH)
    redis_options.each do |value|
      temp.puts(value)
    end

    temp.close

    Subexec.run("redis-server #{temp.path}")
  else
    redis_options = redis_options.join("\n")
    `echo '#{redis_options}' | redis-server -`
  end
end


config.after(:suite) do
   %x{
     cat #{REDIS_PID} | xargs kill -QUIT
     rm -f #{REDIS_CACHE_PATH}dump.rdb
   }
end

WebAPIのテスト

ここで言うWebAPIのテストとは、外部のWebAPI(twitterとか)を使う場合のテストのこと。
これはwebmockというgemを使えば良い。
bblimke/webmock · GitHub

ただ、webmockを使ってしまうとCapybaraがlocalhostにアクセスしたときにもすべてmockが返ってきてしまうので、localhostを除外するようにする
spec_helper.rbに以下のように書く

WebMock.disable_net_connect!(:allow_localhost => true)

Javascriptのテスト


Capybara-Webkit使
thoughtbot/capybara-webkit · GitHub
JavascriptjQuery
JSpoltergeist使
jonleighton/poltergeist · GitHub

Capybara-Webkitrspecfactory_girlCapybara
CapybaragithubActiveRecordshared_connectionDatabaseCleaner使
JStransaction使JStruncate
Capybara.javascript_driver = :webkit

config.before :each do
  if Capybara.current_driver == :rack_test
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.start
  else
    DatabaseCleaner.strategy = :truncation
  end
end

config.after :each do
  DatabaseCleaner.clean
end

画像のテスト

画像関連はCarrierWaveを使ってるんだけど、factory_girlで作られてしまうのでテストが終わった後に消してる。あとテストの場合は通常とは違うディレクトリに書き出してる。

継続的インテグレーション

Jenkinsを使ってgitにpushされたらテストを実行してる。それとは別に朝8時ごろにも流してる。
simplecov-rcovとci_reporterを使って、カバレッジとテスト数の推移をグラフで出してる。
またテストに通ったら、自動的に社内の検証環境にデプロイされるように、ビルドパイプラインの設定をしてる。
Abilieに関してはまだリリースされてないので、Jenkinsも試験的に社内のサーバに入れてるだけで、本番へのデプロイとかはやるかどうかわからない。
まだJenkinsは使い始めたばかりであまりいじってないけど、rails_best_practiceとかも組み込めるといいかなと思ったりしてる。

おわりに

入社した直後に引き継いだプロジェクトはテストも無く、チームにテストを書く文化もなく、業務でちゃんとテストを書いたことがなかったぼくですが、入社半年後くらいからテストを書き始め、少しずつテストを書く文化ができてきてよかったかなと。
とは言っても僕の担当してるプロジェクト以外は相変わらずテストが書かれてないものが多いので、そのあたりが今年の課題な気はしてる。

*1:詳しくはhttp://d.hatena.ne.jp/tohae/20111222/1324533072