RubyのカバレッジツールSimpleCovをPadrino用にカスタマイズして使う
弊社のサービスHachikinはPadrinoというRubyのフレームワークで作っています。ユニットテストフレームワークにはRSpecを使っています。
今回、テストのカバレッジを取りたいと思ったのでSimpleCovというツールを使って見ることにしました。
0. 今回の環境
Rubyでテストするときの一般的な構成だと思いますが、以下のツールを使用しています。テストはGuardとSporkを使っていて、スペックが変更されたときは自動でテストが実行されるような環境になっています。
- Ruby 1.9.3
- Padrino 0.11.2
- RSpec
- Spork
- Guard
1. SimpleCovのインストール
Gemfileに下記の行を追加して、bundle installします。
group :test do
# 省略・・・
gem 'simplecov', :require => false
end
2. Padrino用にカスタマイズした設定を追加
以下の様なファイル(spec/simplecov_custom_profile.rb)を作成します。後で説明しますが、add_groupはカバレッジ結果をどうグループ化するか、という設定になり、ここでは、サブプロジェクト毎のコントローラ、ヘルパーをそれぞれグループ化して出力するという設定をしています。(sub1/controllers, sub1/helpers, sub2/controllers, sub2/helpers・・・みたいにグループ化します)
# -*- coding: utf-8 -*-
require 'simplecov'
# Adapterの定義。ここではpadrinoという名前で定義。
SimpleCov.adapters.define 'padrino' do
add_filter '/spec/'
# サブアプリケーションの一覧
sub_apps = %w(app sub1 sub2 sub3 sub4)
sub_apps.each do |sub_app|
# コントローラグループ
add_group "#{sub_app}/controllers", "#{sub_app}/controllers"
# ヘルパーグループ
add_group "#{sub_app}/helpers", "#{sub_app}/helpers"
end
add_group 'Models', 'models'
add_group 'Libraries', 'lib'
end
3. spec_helper.rbにカバレッジ生成用のコードを追加
spec/spec_helper.rbにカバレッジ生成用のコードを追加します。SimpleCov.startの引数に渡しているのは、2で定義したAdapterの名前を指定します。(railsというAdapterはデフォルトで定義されているようです)Sporkを使用している場合の設定についてはここに記述があります。
2行目などでDRB環境変数が設定されていないときに動作するようになっています。これは、Sporkをdrbを使って動作させているとき有効になっているであろう環境変数ですので、通常開発中にはカバレッジは生成しないような設定になっています。
Spork.prefork do
unless ENV['DRB']
require 'simplecov_custom_profile'
SimpleCov.start 'padrino'
end
# テストのためのその他の設定・・・(省略
end
Spork.each_run do
unless ENV['DRB']
require 'simplecov_custom_profile'
SimpleCov.start 'padrino'
end
# テストのためのその他の設定・・・(省略
end
4. (テストを実行して)カバレッジを生成する
Padrinoのプロジェクトのルートディレクトリで以下のコマンドでテストを実行します。
$ padrino rake spec
テストが終わるとプロジェクトのルートディレクトリにcoverageというディレクトリが作成されていると思うので、このなかのindex.htmlを開いてみます。
するとこんな感じでカバレッジが取れました。タブっぽいのが見えてると思いますが、これは2で設定したadd_groupの定義で、サブアプリケーションごとのコントローラ、ヘルパーがそれぞれグループ化されている結果になります。
PadrinoはRailsと微妙にディレクトリ構造が違うので、SimpleCovがデフォルトで定義しているrailsというAdapterだとうまくグループ化してくれないのでこのような定義にしました。
タブが多すぎて微妙って場合は以下の設定もありかなと思います。ここでは、コントローラとヘルパーをグループ化しているだけになります。
# -*- coding: utf-8 -*-
require 'simplecov'
SimpleCov.adapters.define 'padrino' do
add_filter '/spec/'
# サブアプリケーションの一覧
sub_apps = 'app|sub1|sub2|sub3|sub4|'
# コントローラグループ
add_group 'Controllers' do |src_file|
src_file.filename =~ /(#{sub_apps})\/controllers\//
end
# ヘルパーグループ
add_group 'Helpers' do |src_file|
src_file.filename =~ /(#{sub_apps})\/helpers\//
end
add_group 'Models', 'models'
add_group 'Libraries', 'lib'
end
add_groupの2つ目の引数には、ソースファイル(SimpleCov::SourceFile)を引数にもつブロックを渡せるので、ここでグループ化するための条件を記述できます。(ちなみにsrc_file.filenameはフルパスが返ってきます)
まとめ
ということで、Padrinoでも綺麗にカバレッジが取れるようになりました。今後はJenkinsなどでテストを実行した後に、カバレッジの結果が取れるようにしようかと思います。それはまた次の機会ということで。