Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

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』をどうぞお役立てください。

ツイートより

関連記事

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

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


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。