コードカバレッジ視点で、Rubyでテストを書くときに気をつけること

追記 2017-12-25

Ruby2.5.0で分岐カバレッジのための情報が追加されるみたいなので、それをベースにしたカバレッジツールが出てきそうですね。書いて数日ですが、この記事の内容も古くなりそうなので気をつけてください。

Add branch coverage https://bugs.ruby-lang.org/issues/13901


トレタ Advent Calendar 2017の21日目記事です。

トレタでは、SimpleCov(https://github.com/colszowka/simplecov) を使って、
Railsアプのコードカバレッジを計測しています。
そのときに気をつけていることを、いくつかつか紹介したいと思います。

行単位でしか判断できない

コードカバレッジにはいくつか種類がありますが、SimpleCovで計測できるのは、命令網羅(C0)と呼ばれる
行単位でコードが実行されたかを確認するものです。(これはRubyVMから実行行を取得し、それをもとに作られているためです)
C0カバレッジは比較的網羅率を上げやすいかんたんなものですが、逆にそれだけでは問題に気づけないケースがでてきます。

3項演算子

def div(x)
  1 / (x ? 1 : 0)
end

xがtrueな値のテストだけが書いてあるとして、カバレッジを計測すると100%になります。

スクリーンショット 2017-12-24 12.11.59.png

このケースでfalseを入れると例外が起きてしまいます。あえてifで書いてみると、そのパスが通らないことがはっきりわかります。

スクリーンショット 2017-12-24 12.15.34.png

後置きのif/unless

a = 1
a = 2 if x == true

これも3項演算子と同じで、xがどういう値であれ、この行を通ってしまうので、xがtrueのケースを書かなくても、この行が通ったことになります。a = 2の部分を通っていないケースに気をつけましょう。

ブロック

sum = some_arr.select { |i| i > 0 }.reduce { |r, i| p i ; r + i }

このケースでは、some_arrに0以下の値しかない場合に、selectで空配列になってしまうので、そのあとのreduceはなにもしません。reduceに限らず、ブロックを使っているときに、実はそれが実行されないケースのテストしか書いていないというのに気をつけましょう。

たとえばsum([-1, 0])みたいなテストだけしても100%になります。

スクリーンショット 2017-12-24 12.18.32.png

改行をいれても変わりません。行単位といっても、物理的な改行ではなくてRubyのプログラムとして一行単位なためです。

スクリーンショット 2017-12-24 12.25.31.png

doブロックにしてみると、行が変わるのでテストが通っていないことがわかります。

スクリーンショット 2017-12-24 12.26.07.png

メタプログラミング

メタプログラミングを使ってメソッドやクラスを動的に生成していると、
その部分に対してテストが通っているかをカバレッジで判断できないケースがが多くあります。

[0, 1, 2].each do |i|
  define_method "m#{i}" do
    1 / i
  end
end

m0, m1, m2が定義されますが、どれか一つでも通せはこの行を通ったことになります。

スクリーンショット 2017-12-24 12.32.24.png

また文字列からevalするケースではカバレッジは無力です。

参考 SimpleCovのカバレッジ(網羅率)

まとめ

思いついたケースをまとめただけなので、まあまだ他にも気をつけるケースはあると思います。

それから、カバレッジのために3項演算子や後置ifやメタプログラミング使うな、という話ではなくて、
使っているカバレッジの性質を理解して、そういう部分にはテストを書くときに注意するとか、
より危なそうなケースでは、あえて冗長にしてもいいし、そのへんは各自で判断してやっていくのがいいと思っています。

もっと強力なカバレッジツールがあれば、こういうことに気をつけなくてもいいようになる可能性もありますが、現状は見当たらないので(あればおしえてください)、テストが意図通りに動作を確認できているかの一つの道具/指標として、SimpleCov使っていきましょう。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.