概要
RSpecでモジュールで定義した定数との同値テストの結果を見易くする。
(これ、需要は少なくないと思うので、標準の方法でもあるのではないかと疑っています。知ってる方いたら教えて頂けると幸いです)
前振り
RSpecのテストを書いていて、ある対象がモジュールで定義した定数と一致すること、というテストケースを書くことがある。
例えば、こんなテストケース。
# プロダクトコード抜粋
module Status
SUCCESS = 0
ERROR = -1
end
# テストコード抜粋
status = Status::SUCCESS
expect(status).to eq Status::Error
# => expected: -1
# => got: 0
この失敗するテストの結果は、人間にとって見易いものではない。
我々が知りたいのは0とか-1とかいう数値ではなく、SUCCESSとかERRORとかいう意味のある名前である。
解決方法
以下のようなmatcherを実装する。
RSpec::Matchers.define :const_eq do |mozule, exp_symbol|
match do |act_val|
mozule.const_get(exp_symbol) == act_val
end
failure_message do |act_val|
act_symbol = mozule.constants(true).find { |c| mozule.const_get(c) == act_val }
act_msg = if act_symbol.nil? then "ACTUAL: unknown value(#{act_val})"
else "ACTUAL: #{mozule.name}::#{act_symbol}(#{act_val})"
end
exp_val = mozule.const_get(exp_symbol)
"EXPECT: #{mozule.name}::#{exp_symbol}(#{exp_val})\n" << act_msg
end
end
使用例
# プロダクトコード抜粋
module Status
SUCCESS = 0
ERROR = -1
end
# テストコード抜粋
status = Status::ERROR
expect(status).to const_eq Status, :SUCCESS
# => EXPECT: Status::SUCCESS
# => ACTUAL: Status::ERROR
expect(999).to const_eq Status, :SUCCESS
# => EXPECT: Status::ERROR
# => ACTUAL: unknown value(999)
改善予定
-
--format documentation
したときにも見易くするためにdescriptionを定義する。 - より細かな制御ができるmatcherを生成する方法はその2で紹介する。