今現在RSpecの学習のために『Everyday Rails - RSpecによるRailsテスト入門』を読んでいるところなのですが、3章でわからない記述が出てきたので個人的に調べてみて理解した内容をまとめます。RSpec初学者向けの小粒な記事になります。
次のコードは、3章の「バリデーションをテストする」という見出しの最初に示されている実例です。Userモデルの存在性のバリデーションがうまく働いているかどうかをテストするexampleになります。
# 名がなければ無効な状態であること
it "is invalid without a first name" do
user = User.new(first_name: nil)
user.valid?
expect(user.errors[:first_name]).to include("can't be blank")
end
このブロックの最後の2行についてなんですが、私が初めに見たときは
単に無効であることを調べるだけならexpect(user.valid?).to eq false
の1行で済む話じゃないの?なんでわざわざ「エラー文を生成→その内容を確認」なんていう書き方をするんだろうか
と、疑問に思ってしまったのでした(私だけでしょうか?)
しかし調べてみるとこれにはちゃんとした理由があるようです。
というのも、先程の2行をexpect(user.valid?).to eq false
という1行にしてしまった場合、
仮にテストがパスした(user.valid?がfalseを返した)としても、本当に存在性のバリデーションに引っかかったのかどうかが分からない(別のバリデーションが原因で無効になった可能性が生じてしまう)といった問題が出てくるのです。
一方で、元の記述であれば生成したインスタンスが無効であることを調べると同時に、無効になった原因まで特定することができるようになります。
user.valid? #エラー文を生成する
expect(user.errors[:first_name]).to include("can't be blank") # エラー文が存在性の検証に関するものであることを調べる
このように、テストの誤検知を防ぐためにも「今書こうとしているテストの目的は何か?」というところを、より突き詰めた書き方を意識していかないといけないようです。