概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: RSpec - you should avoid let and before blocks to use natural flow
- 原文公開日: 2018/02/06
- 著者: Paweł Dąbrowsk
Rails tips: RSpecのlet
ブロックやbefore
ブロックは基本避けるべき(翻訳)
RSpecの作者はそれなりの理由があってbefore
やlet
ブロックを考案しましたが、本当に必要でない限りこれらの利用は避ける方が賢明です。理由は以下のとおりです。
- テストの本体から
let
の定義にジャンプ(またはその逆のジャンプ)することで、テストの自然な流れを妨げることになります。 let
を使うとテストが遅くなります。let
がシンプルなメソッドに変換されるのは最後の段階だからです(memory usage benchmark)を参照(訳注: リンク切れです)。- specが読みづらくなります。正しいコンテキストを追うにはあちこちにジャンプしなければなりません。
- 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
次はbefore
やlet
を使わない場合です。
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でご覧いただけます(訳注: リンク切れです)。また、多くの方が私の記事を読み誤っています。私は「いついかなる場合でも」before
やlet
を使うなと申し上げたいのではありません。let
やbefore
がspecの高速化などに有用な場合は(特に複雑なケースでは)確かにあります。しかし私は常にコードをシンプルに書くようにしており、その方が有用性が高いことに気づいたのです。
RSpec & TDDの電子書籍を無料でダウンロード
もっと稼ぎたい方や会社をさらに発展させたい方へ: テスティングのスキルの重要性にお気づきでしょうか?テストを正しく書き始めることが、唯一のファーストステップです。無料でダウンロードいただける私の書籍『RSpec & Test Driven Developmentの無料ebook』をどうぞお役立てください。
ツイートより
これ読んでたけど、ここに乗ってる let のコード例は使い方が悪いだけでしょ… / Rails tips: RSpecの`let`ブロックや`before`ブロックは基本避けるべき(翻訳) - https://t.co/oWZNIgSH95
— バンビちゃん@実際クソザコナメクジ (@pink_bangbi) July 5, 2018