LoginSignup
3
1

More than 3 years have passed since last update.

Rspec速度改善 #1

Last updated at Posted at 2020-04-08

今回に5つのRspecの速度改善方法をご紹介したいと思います。

1. Parallel Testing
2. Adding gem test_prof
3. Optimize Setup Time
4. Using stubs and mock
5. Using trait in Factory


1. Parallel Testing

parallel_testsとは

  • マルチコアCPUで並列実行するテスト用のGem

parallel_testsを導入する方法

Gemのホームページに参考してください。

Note

  • CPUのRamをよく食い尽くすので実行する間に他の作業を離してください。w

2. Adding gem test_prof

問題

# bad
it { is_expected.to be_success }
it { is_expected.to have_header("X-TOTAL-PAGES", 10) }
it { is_expected.to have_header("X-NEXT-PAGE", 2) }
its(:status) { is_expected.to eq(200) }

# good
it "returns the second page", :aggregate_failures do
  is_expected.to be_success
  is_expected.to have_header("X-TOTAL-PAGES", 10)
  is_expected.to have_header("X-NEXT-PAGE", 2)
  expect(subject.status).to eq(200)
end
  • itを呼ぶと、もう一回subjectを呼ぶので、時間が遅くなっています
    → itを一回だけ呼ぶようにした方が良いと思う

変更方法

  • test_profのGem導入: ホームページに参考してください
  • Rubocop修正: こちらに参考してください
  • 以下のコマンドを実行したら、全部#badの所を自動に#goodになる
rubocop -r 'test_prof/rubocop' --only RSpec/AggregateFailures -a spec/

Rspecを確認した結果

rspec spec/api/gmo/transaction_api_spec.rb

BEFORE:
Finished in 7.53 seconds (files took 7.74 seconds to load)

AFTER:
Finished in 2.08 seconds (files took 7.39 seconds to load)
  • 1ファイルだけ確認したが、早くなってきた!
  • 皆さんもテスト書く時、注意してくださいね!

3. Optimize Setup Time

BEFORE:

  • テストのプロセスに変更されないデーターがあったら、letの代わりにbefore(:all)ブロックにインスタンス変数に移動した方が設定時間減らすできると思います。
context "a" do
  ...
  let(:shop){create :shop}
  ...
end

context "b" do
  ...
  let(:shop){create :shop}
  ...
end

context "c" do
  ...
  let(:shop){create :shop}
  ...
end

# → テストケースによって`shop`を作る

AFTER:


before(:all){@shop = create :shop}

context "a" do
  # @shopを使える
end

context "b" do
  # @shopを使える
end

context "c" do
  # @shopを使える
end

# → `shop`を一回だけ作る

4. Using stubs and mock

create, build, build_stubbedの違い

  • 多分他のTopicに説明が多いと思うですが、簡単に言うと
■ create: 対象のModelと関係あるModelがDBに作成される
■ build: 対象のModelではなく、関係あるModelしかがDBに作成されない
■ build_stubbed: 対象のModelも、関係あるModelも何もDBに作成されないが、
                 ちゃんと本物のModelとして使える
  • build_stubbedが上の3つの中に一番早いなので、DBにあまり関係ないとか、Modelの関係が必要ないテストケースなどに使った方が速度は早くなります。
  • できるだけ、この順番で使えばもっと早くなると思う
    double → build_stubbed → build → create
  • build_stubbedの場合、DBに保存やアソシエーション先をDBに保存できませんので、ご注意ください。

Using allow

bad.rb

context "a" do
  before do
    form.available_from_kind_is_use = nil
    form.available_from_kind_backend = nil
    form.available_from_kind_frontend = nil
    form.save!
  end
end
good.rb

context "a" do
  before do
    allow(form).to receive(:available_from_kind_is_use).and_return nil
    allow(form).to receive(:available_from_kind_backend).and_return nil
    allow(form).to receive(:available_from_kind_frontend).and_return nil
  end
end
  • DBを変更必要はない場合、allowを使った方が良いです

5. Using trait in Factory

BEFORE

users.rb

FactoryGirl.define do
  factory :user do
    name "Hung"
    location build(:location)
  end
end
user_spec.rb
it do
  user = build :user, name: "Hung"
  expect(user.name).to eq("Hung")
end
  • 上のケースだと、locationが必要ないけど、もう作られた

AFTER


FactoryGirl.define do
  factory :user do
    name "Hung"

    trait :with_location do
      location build(:location)
    end
  end
end
  • locationが必要なテストケースだけに:with_location使った方が良いと思います
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1