RSpecで変化を検証する: 遅延評価とbefore
今日はメソッド適用前後の表示順の変化をテストで検証するケースで悩みました。
メンターさんに教えていただいて、let定義の後にbeforeで表示順を入れ替え、検証すればよいことを学びました。
before 自体は知っていたものの、今回活用できるとは思っておらず、理解不足を痛感しました。
beforeブロックの中に書かれたコードは内側の角テストが実行される前に実行されます。
なお、beforeのスコープはbeforeが記述されたdescribeやcontextブロックになります。
一時的にlet定義の状態を変えたい場合にはちょうどよいです。
describe "#self.management" do let!(:student) { create(:classroom) } let!(:teacher) { classroom.creator } context "教師を変更すると、新しい教師が先頭に表示される" do before { member.update!(user: classroom.user) } #例外を把握したいので「!」をつける it "管理者メンバーが最初に表示される形に並び替えられる" do expect(classroom). #( )内にはメソッド名 to eq([ teacher, student, ]) end end
beforeにはいくつか種類があります。
before(:each)
describeまたはcontextブロック内の各(each)テストの前に実行されます。
エイリアスにbefor(:exmple)があります。
beforeだけでもよいです。beforeはbefore(:each)を簡略に示したものです。
before(:all)
describeまたはcontextブロック内の全(all)テストの前に一回だけ実行されます。
エイリアスはbefore(:context)です。
before(:suite)
テストスイート全体の全ファイルを実行する前に実行されます。
before(:all) とbefore(:suite)は独立したセットアップの前に使う分にはテストの実行時間を短くするのに役立ちますが、テスト全体の可読性を下げてしまう可能性もあります。
できる限りbeforeを使うほうが良いようです。
なお、もう一点注意が必要なことがありました。letの遅延評価です。
遅延評価を実現するletメソッド
letは呼ばれたときに初めてデータを読み込む遅延評価(遅延読み込み)を実現するメソッドです。
letは明示的に呼び出されないとデータは作成されません。
その点を考慮しないと、expectとgotの数値に差異が生じてテストに失敗してしまいます。
(私はこの要因でテストに失敗していると気づけず、他のコードを不必要に修正してしまっていました。)
なお、let!と「!」をつけると遅延読み込みされず即座に実行します(逐次評価)。
つまり、let!と定義することで明示的に記述しなくても呼び出せる状態になります。
不要なデータを持ち続けていないかという点については、考慮したほうが良さそうです。
また、letとlet!は見分けがつきにくいため、beforeとインスタンス変数の組み合わせと比較して可読性の高い方を選択するとベターです。
「Every Day Rails」を再読しようと思います。