Rails tips: RSpecテストを遅くする悪い書き方3種(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: 3 things that slow down and make your RSpec tests worse 原文公開日: 2018/03/21 著者: Paweł Dąbrowsk Rails tips: RSpecテストを遅くする悪い書き方3種(翻訳) テストが遅くなる原因はそれはもうさまざまで、コードに関係するものもあればそうでないものもあります。今回は、specを高速化して改善するちょっとした変更のコツをご紹介します。 1. trueかfalseを常に期待する場合はbe_truthyやbe_falseyを避ける まずは以下のコードをちょっとご覧ください。 expect(true).to be_truthy expect(1).to be_truthy expect(‘string’).to be_truthy expect(nil).to be_falsey expect(false).to be_falsey どのexpectationもパスしますので、falseやtrueが返っているとお考えになるかもしれませんが、何か不具合があってこれ以外のものが返されると、テストでキャッチできなくなってしまう可能性があります。 解決方法 値そのものを指定します。 expect(true).to eq(true) expect(1).to eq(true) expect(‘string’).to eq(true) expect(false)to eq(false) expect(nil).to eq(false) 2. FactoryBot.buildは避ける 訳注: 原文のFactoryGirlはリンクを除いてFactoryBotに置き換えました。 FactoryBot.buildを呼び出してもデータベースにレコードは作成されないとお思いかもしれませんが、まあUse Factory Girl’s build_stubbed for a Faster Test Suiteをご覧ください。ファクトリー内で関連付けが宣言されていると、レコードが作成されてしまいます。たとえば次のようなファクトリーがあるとしましょう。 FactoryBot.define do factory :user do contact company end end そしてFactoryBot.build :userを呼び出すと、データベースにレコードが2件作成されます。テストの冒頭でファクトリーを初期化してexampleを10件実行すれば、レコードが20件も作成されます。このレコードが不要であれば、改善の余地が大いにあります。 解決方法 FactoryBotl.build_stubbedを使うことです。こちらはデータベースにレコードを作成することはありません。 3. スタブの代わりにModel.newするのは避ける 以下の例で考えてみましょう。シンプルなSampleClassクラスとSampleApiクラスがあります。 class SampleApi def login; end end class SampleClass def call api.login end private def api SampleApi.new end end そしてSampleClass#callメソッドをテストしたいとします。 require ‘spec_helper’ describe SampleClass do describe ‘#call’ do it ‘calls API’ do api = SampleApi.new allow(SampleApi).to receive(:new).and_return(api) allow(api).to receive(:login) sample_class = SampleClass.new sample_class.call expect(api).to have_received(:login).once end end end ここまではよさそうに見えます。お次はSampleApiに新しいメソッドを追加してそれを#loginメソッドより前に呼び出したいとします。やってみましょう。 class SampleApi def login;end def before_login_action;end end class SampleClass def call api.before_login_action api.login end private def api @api ||= SampleApi.new end end テストを実行してみるとやはりgreenのままです。クラスの実装を変更したのにこうなったというのは悪い知らせです。スタブ化されてないインスタンスを使うと、実行されたメソッドに対する制御が失われてしまいます。この手の問題を洗い出すのは大変で、テスト駆動開発(TDD)アプローチを行わない開発者がメソッドを更新した場合は特にそうです。 解決方法 代わりにinstance_doubleを使います。api = SampleApi.newをapi = instance_double(SampleApi, login: double)に置き換えれば、ちゃんとエラーが出力されます。 Double “SampleApi (instance)” received unexpected message :before_login_action with (no args) この解決法は元の書き方とくらべても決して遅くはなく、しかも完全にコントロール可能です。メソッドがn回実行されることを期待するメソッドに対してinstance_doubleを組み合わせれば、期待どおりの結果が得られます。 お知らせ: RSpec & TDDの電子書籍を無料でダウンロード もっと稼ぎたい方や会社をさらに発展させたい方へ: テスティングのスキルの重要性にお気づきでしょうか?テストを正しく書き始めることが、唯一のファーストステップです。無料でダウンロードいただける私の書籍『RSpec & Test Driven Developmentの無料ebook』をどうぞお役立てください。 関連記事 Rails: … Continue reading Rails tips: RSpecテストを遅くする悪い書き方3種(翻訳)