🕵️♂️
ぼっち演算子を無闇に使うとブランチカバレッジが悪化する
ブランチカバレッジが何かと言うと下記に記載があります。
↑では、三項演算子の例と後置ifの例が乗っています。
下記の例では、numberが奇数と偶数の両方の分岐を通すようなテストが書けていれば100%です。
number.odd? ? "odd" : "even"
本題のぼっち演算子の場合はこんな感じです。
sample.rb
def sample(a:)
return if a.nil?
p a&.to_s
end
sample(a: nil)
sample(a: 42)
上記の例だとぼっち演算子の手前で止まってnilが出力されるようなパターンのテストは書けそうもありません。
この時のブランチカバレッジがどうなるか実際にsimplecovを使って調べてみます。
simplecovを使うのに、わざわざrailsとrspecを準備する必要はなく下記のようなコードで調べられます。
require 'simplecov'
SimpleCov.start do
enable_coverage :branch
end
require "#{__dir__}/sample.rb"
上記のコードをrubyで実行して、生成されたindex.htmlをワンラインサーバなどで見ると、下記の通りの結果になります。
※おすすめのワンラインサーバはserveです


lines coveredは100%ですが、branches coveredは75%になっていて、ぼっち演算子のところがちょうど赤くなっています。
また下記のようなパターンだとnilチェックすらブランチカバレッジが悪化する原因になります。
sample3.rb
class Sample
def initialize(a:)
raise ArgumentError, 'a cannot be nil' if a.nil?
@a = a
end
def sample
return if @a.nil?
p @a.to_s
end
end
Sample.new(a: 42).sample
Sample.new(a: nil).sample rescue nil

このパターンは割と実際のコードに近い気がします。インスタンス変数を使うと初期化しているコードとインスタンス変数を利用しているときのコードが離れたりしていて、とりあえずnilチェックしておこうとなりやすいと思います。
ただ、上記で挙げたパターンは、ブランチカバレッジが悪化したところで、実際のコードの品質には何も問題ないはずです。強いて、困り事をあげるとすれば、ciが落ちたりするくらいでしょうか。。。
今回使用したコードはこちらです
Discussion