rspecのdescribe, context, subject, letなどの書き分け
Everyday Railsを読んでみて、rspecの利便さに改めて気付かされました。 特にAPI周りの実装をすることの多かった自分としては、capybaraによるfeatureテストなんかはこんなことがこんなに簡単にできるのかと驚きました。
しかし、自分としては知りたかった、describe
やcontext
、let
の書き分けといった細かな部分についてはあまり深く触れていなかったので、
自分のいままでの経験上で「こんな感じでやってます」というのを、まとめついでに紹介したいと思います。
テスト名の宣言 - describe, context, it
describe
とcontext
については、どちらも同じ挙動をするので、テストとしてはどっちで書いても機能するのですが、
言葉の意味合いから下記のように使い分けています。
it
については、エラーがでたときに内容を理解できればいいかなということで、複雑な内容でない限りは記述してないことのほうが多いです。
区分名 | 使い方 |
---|---|
describe | テストグループ ( クラス名, メソッド名, ) |
context | テスト条件 ( 変数の違いや前提条件の違い ) |
it | テスト結果 |
describe API::UserAuth do describe "POST /api/session" do context 'with valid password and email' do it do .... end end context 'with invalid password' do it do ... end end context 'when user has already signed in ' do it do ... end end end end
変数宣言について - subject / let / インスタンス変数
どちらも変数を扱う記述ですが、subject
の使い道としては、そのテストする内容自身を記述します。
一方、let
はそれ以外のテスト内で扱う変数の記述します。
インスタンス変数については、原則使わないほうが良いと思われる。というのも、テストのために、before
文の中でインスタンス変数を宣言する形となってしまい、記述が見辛くなってしまう。
書き方を工夫すれば、let
で代用できるので、こちらを扱うほうが適切だと思われる。
なお、subject
については名前付きで宣言することもでき、sign_in
のように返り値のない、副作用の生じるメソッドなどで、その対象を名前付きのsubject
をとして宣言して、テスト対象であることを明示するといいかも。
区分名 | 使い方 |
---|---|
subject | テスト対象 = expectの引数になるもの |
let | expectの引数になり得ないもの |
@hoge | 使わない |
describe User do describe '#sign_in' do subject { user.sign_in(email, password) } subject(:user) { User.new(email: "hoge@example.com", password: "password") } context "with valid password and email" do let(:email) { "hoge@example.com" } let(:last_name) { "password" } it { expect { subject }.to change(UserSession, :count).by(1) } it { expect { subject }.to change(user, :session) } end end
beforeについて
before
については、テストを行う上での前提条件となるような内容を記述する。
主に、let
での変数宣言だけでは対処できないような処理はこのbefore
に書くようにしてます。
context 'when user has already signed in' do before { user.sign_in(email: "hoge@example.com", password: "password") } it do ... end end
最後に
綺麗に書けたテストは見やすく、メンテもしやすいです。
テストだからと軽視せずに、テストも綺麗に書けるようになるといいですね!