Rubyのテストカバレッジのためのgemのsimplecovが良かった。あと、Rubyのバグを直してもらった。

最初に

Rubyでテストカバレッジとしては、
Rubyコアにcoverageライブラリがあり、
Gemとしてはsimplecovというのが有名ぽいです。

simplecovを使ったら良かったという話とRubyのバグが見つかったことを書きます。

simplecovの使い方

インストール方法

GitHubの公式simplecov-ruby/simplecovにやり方は書いてますね。

Gemfile*.gemspecファイルに、simplecovをインストールするように書く。

gem 'simplecov'

本番環境で使うものではないので、本番環境から除いてインストールにするとよさそうですね。
とりあえず使うことを目的として、ここでは1番シンプルなものを書きました。

自分のケースですと、Gemの開発でテストカバレッジを調べたかったので、以下のように書きました。

spec.add_development_dependency "simplecov"

Gemの開発者だけが使う場合は、このように書けばいいはず。

そして、bundle installコマンドを実行して、インストールします。

実際の使い方

GitHubの公式simplecov-ruby/simplecovに書かれていますが、 次に記述を追加します。

require 'simplecov'
SimpleCov.start

このコードは、simplecovライブラリをロードして、SimpleCov.start(カバレッジ計測の開始)を実行してるだけです。
この記述を書く場所ですが、この記述を書いたあとにrequire_relativeなどで呼び出したファイルを計測してくれるので、次のように書きます。

require 'simplecov'
SimpleCov.start

require_relative 'convolution_test'
require_relative 'crt_test'
require_relative 'dsu_test'

これを書いたコードを実行してあげます。
そうすると、coverageディレクトリに色々とファイルが作られるのですが、 その中にindex.htmlがあり、これをブラウザで開いてあげます。

Image from Gyazo

めっちゃ綺麗でわかりやすいです!!
% coverdが100%であれば全てのコードが実行されたことになり、
テストが網羅的に書かれていそうだなとわかります。

実際にファイルでどこの行が実行されたのか、何回実行されたのかまで見ることができます。 赤色のコードが実行されてないコードです。
こうすることで、テストできてないコードや実行されてないデッドコードがわかり便利です。

Image from Gyazo

バグが見つかる

ところで、上の画像なのですが、赤色のコードを調べてみると明らかに実行されていました。
バグのようです。simplecovのバグかなと思い、Issueを見たのですが、それらしき報告はありませんでした。
Issueを立てようと思ったのですが、Rubyにも標準添付のcoverageがあって、そっちを試したらどうなるのだろうと思ったら同じ現象が起きました。

具体的にどのようなファイルで、バグがあるのかというと、次のようなwhileの中にwhileがあるケースの一部で、中のwhileがカウントされません。

n = 3
while n > 0
  n -= 1 while n > 0
end

これをカバレッジ計測対象のwhile_in_while.rbとします。
このファイルに対して、次のように計測してみます。

require "coverage"
Coverage.start
load "while_in_while.rb"
pp  Coverage.result
# {"while_in_while.rb"=>[1, 1, 0, nil]}

while_in_while.rbの3行目のn -= 1 while n > 0は実行されているはずなのに、実行された回数が0回になっています。
なお、4行目のendは実行されるべきものではないので、nilを返しています。

ここで:all指定で全モードで計測すると、:lines=>[1, 1, 1, nil]で中のwhile文が1回実行されているとなりました。
違う結果になって、バグか何かだろうと確信しました。

require "coverage"
Coverage.start(:all)
load "while_in_while.rb"
pp  Coverage.result
# {"while_in_while.rb"=>
#   {:lines=>[1, 1, 1, nil],
#    :branches=>
#     {[:while, 0, 2, 0, 4, 3]=>{[:body, 1, 3, 2, 3, 20]=>1},
#      [:while, 2, 3, 2, 3, 20]=>{[:body, 3, 3, 2, 3, 8]=>3}},
#    :methods=>{}}}

気持ち的にはn -= 1が3回実行されているから3回でもありなのではと少し思いましたが、1回でも良さそうです。
とにかくモード指定しなかったときの行のカウント等が0回となっており、0回と1回以上とでは大違いです。

simplecovがRubyのcoverageライブラリを使っているから同じことが起きるのかなと思い、
Rubyコア側に報告することにしました。

報告したら、すぐ変更してもらえた

whileの中にwhileを書く機会のあるコードを書く人は少数派で、これに遭遇する人は少ないだろうなと思いつつも、
0と1は違うので報告することにしました。

報告したら、コミッターのmameさんにすぐ対応してもらえました。良かった。

最後に

テストカバレッジで100%になっていると気持ちがいいですし、とても安心です。

あと、Rubyリファレンスマニュアル(るりま)のcoverageの説明の情報が古かったのでPRをだしておきました。PRがたまっていて時間がかかりそうですが、そのうち対応されると思います。(1ヶ月後とかになるかも)

テストカバレッジの手法をあまり知らないので、知ってたら教えてくださると嬉しいです。
「こんなgemがあるよ」とか「こんなgemを使ってます」とか。