Rails tips: RSpecの`let`ブロックや`before`ブロックは基本避けるべき(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Rails tips: RSpecのletブロックやbeforeブロックは基本避けるべき(翻訳)

RSpecの作者はそれなりの理由があってbeforeletブロックを考案しましたが、本当に必要でない限りこれらの利用は避ける方が賢明です。理由は以下のとおりです。

  1. テストの本体からletの定義にジャンプ(またはその逆のジャンプ)することで、テストの自然な流れを妨げることになります。
  2. letを使うとテストが遅くなります。letがシンプルなメソッドに変換されるのは最後の段階だからです(memory usage benchmark)を参照(訳注: リンク切れです)。
  3. specが読みづらくなります。正しいコンテキストを追うにはあちこちにジャンプしなければなりません。
  4. spec同士に依存関係が生じます。specは分離するべきです。

letブロックやbeforeブロックを使った場合と使わない場合でどう変わるかを、以下のテスト例で考えてみましょう。

require 'spec_helper'

describe Users::NameService do
  describe '#name' do
    let(:user) { instance_double(User, posts?: false) }

    it 'ユーザー名を返す' do
      expect(described_class.new(user).name).to eq(user.name)
    end

    context 'ユーザーにpostsがある場合' do
      before { allow(user).to receive(:posts?).and_return(true) }

      it 'ユーザー名を返す' do
        expect(described_class.new(user).name).to eq("#{user.name} (has posts)")
      end
    end
  end
end

次はbeforeletを使わない場合です。

describe Users::NameService do
  describe '#name' do
    it 'ユーザー名を返す' do
      user = instance_double(User, posts?: false)

      expect(described_class.new(user).name).to eq(user.name)
    end

    it 'ユーザーにpostsがある場合ユーザー名を返す' do
      user = instance_double(User, posts?: true)

      expect(described_class.new(user).name).to eq("#{user.name} (has posts)")
    end
  end
end

2番目のテストではストーリーを2つに分けてあり、一方を理解するためにitブロックの外まで読む必要はありません。テストコードの重複は若干ありますが、場合によってはDRY(don’t repeat yourself)ルールを守るよりも読みやすさの方が重要です。しかも2番目のテストの方が若干高速です(テストが大規模になると実感しやすくなります)が、重要なのは、ロジックや読みやすさを損なわない範囲でできるだけspecが高速になるようにテストを書くことです。さらに、2番目のテストではスタブも1個少なくて済むというメリットもあります。

beforeブロックやletブロックをどうやっても省略できない例はあるものでしょうか?もしご存知でしたらぜひコメント欄までどうぞ。

追記(2018/02/10)

本記事にベンチマークの結果を追記しました。記事を書く前にベンチマークを取っておくべきでした。ベンチマークはgistでご覧いただけます(訳注: リンク切れです)。また、多くの方が私の記事を読み誤っています。私は「いついかなる場合でも」beforeletを使うなと申し上げたいのではありません。letbeforeがspecの高速化などに有用な場合は(特に複雑なケースでは)確かにあります。しかし私は常にコードをシンプルに書くようにしており、その方が有用性が高いことに気づいたのです。

RSpec & TDDの電子書籍を無料でダウンロード

もっと稼ぎたい方や会社をさらに発展させたい方へ: テスティングのスキルの重要性にお気づきでしょうか?テストを正しく書き始めることが、唯一のファーストステップです。無料でダウンロードいただける私の書籍『RSpec & Test Driven Developmentの無料ebook』をどうぞお役立てください。

関連記事

テストを不安定にする5つの残念な書き方(翻訳)

TestProf: Ruby/Railsの遅いテストを診断するgem(翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ