Rspec入門。Rspecのマッチャ、to, eq, be, be_truthy/falsey,change
Rspecテストフレームワークなので当然期待する結果を検証する必要がありますが、Rspecではさまざまなマッチャが用意されています。
今回はそれらマッチャを淡々と紹介していきます。
to/to_not/not_to
まずは簡単なところから、rspecでは、to,to_notの後にeqなどのマッチャを指定して期待値を記述していきます。1番ノーマルな記述方法が
subject { 1 + 1 }
is_expected.to eq 2
で1+1が2であることを確認するテストになります。
反対に1+1が3でないことを確認したい場合は
is_expect.to_not eq 3
というようにtonotを使って記述をします。nottoでも同様です。
A = B であることを確認するeqマッチャ
先ほども少し紹介しましたがeqマッチャでA=Bであることを確認できます。
subject { 1 + 1 }
is_expected.to eq 2
不等号を使用した値の検証 be
beは等号・不等号組み合わせて、値を検証することができます。
subject { 1 + 1 }
is_expected.to be >= 2
true/falseで評価される値の検証 be_truthy/be_falsey
eqマッチャを知っている人からするとbetruthy/befalseyが使われる理由に???となる人がいるかもしれませんが、betruthy/befalseyは「真っぽいもの/偽っぽいもの」を期待値とするときに使用します。 「っぽい」というあやふやな表現を使っていますが、rubyにおいて偽と判断される値はfalseとnilだけなので、befalseyは「値がfalse,nil」の時に検証をパスします。反対にbetruthyはそれ以外の値の場合にパスします。
以下にわかりやすいように例を載せておきます。
expect(nil).to eq be_truthy // 失敗
expect(nil).to eq be_falsey // 成功
expect(false).to eq be_truthy // 失敗
expect(flase).to eq be_falsey // 成功
expect('hogehoge').to eq be_truthy // 成功
expect('hogehoge').to eq be_falsey // 失敗
expect(1).to eq be_truthy // 成功
expect(1).to eq be_falsey // 失敗
eq true/eq falseのようなマッチャでは厳密に値がture/falseでないと検証をパスしないので、検証するコードによって使い分けましょう。
データの変更を検証するchange
changeマッチャでは、データベースのレコードが変更された場合の変化量や値の変更を検証できます。expect/change句にブロック({})を渡している部分に注意してください。
subject { User.create(name: 'Beth', email: 'beth@example.com') }
it { expect { subject }.to change { User.count }.by(1)
このコードではユーザを作成した際にUserテーブルのレコード件数が+1されたことを確認しています。changeマッチャはby/from/toなどのメソッドを使って、コード実行前後の値の検証を行うことができます。
by/from/toで書く方法には様々なものがありますが、それぞれ特徴があるのでテストに合わせて使い分けをしていきます。
subject { User.create(name: 'Beth', email: 'beth@example.com') }
it { expect { subject }.to change { User.count }.by(1)
it { expect { subject }.to change { User.count }.from(0).to(1)
it { expect { subject }.to change { User.count }.to(1)
例のbyを使ったパターンでは、テスト前のレコード件数に関わらずレコードが1つ増えたことを検証するコードになります。 次にfromとtoを使ったパターンでは、テスト前にすでにユーザが存在していた場合はテストが失敗します。こちらはあくまでユーザが 0 -> 1 になったことを検証しているので、byを使った検証とは意味がことなります。 最後にtoだけを使った場合は、テスト実行後にレコードが1つになっていることを期待しているものですので、0 -> 1はもちろん、2 -> 1, 5 -> 1 のように値が変化した場合にテストを通過します。
by/from/toは便利なメソッドですが、それぞれ意味するところが微妙に異なるので注意しましょう。「ユーザレコードが一つ作成されたこと」を検証したい場合は、例の3番目の検証の仕方は不適切なので注意しましょう。
例外の発生を検証するraise_error
異常系などで例外が発生すること、あるいは例外が発生しないことを検証したい場合は、raise_errorを使用します。
class User < ApplicationRecord
validates :name, presence: true
validates :email, presence: true
end
//~~~~~~
// emailが設定されていないのでバリデーションエラーとなる。
subject { User.create!(name: 'Beth') }
it { expect { subject }.to raise_error }
例では、Userを作成する際に必須のパラメータが設定されていないのでバリデーションエラーが発生し、ActiverRecord::RecordInvalidのエラーが発生します。 これを検証するのがraise_errorです。「エラーが発生する」ことだけでなく「ActiveRecord::RecordInvalidのエラーが発生すること」を検証したい場合は引数にエラーオブジェクトのクラスを渡します。
subject { User.create!(name: 'Beth') }
it { expect { subject }.to raise_error(ActiveRecord::RecordInvalid) }
とします。例外が発生しないことを検証する場合は、to_notを使用します。
it { expect { subject }.to_not raise_error }
まとめ
ここまでRspecのマッチャについて淡々と説明してきましたがいかがでしたでしょうか?これらのシンタックスはなかなか使いこなせるようになるまでは大変で僕自身でもドキュメントやブログをなんども見返しながら繰り返し反復して往復します。一回で覚えようとせずに、ひとつずつ着実に覚えておくことがコツです。プログラミングをしていると、「このやいだやったばかりなのにもう忘れてしまった・・・」と落ち込むことも多いですが、それでもめげずに何回も繰り返すことで身になってくるので、なんどもチャレンジしてみて下さい。