Help us understand the problem. What is going on with this article?

Bullet をテスト環境で実行する

More than 3 years have passed since last update.

Webアプリケションのパフォーマンスに多く影響してしまう N+1 問題。
正直製品レベルのアプリケーションだと基本的にないのが当たり前だと思っていますが、うっかりミスで残っちゃったりするのも事実。
なので N+1 問題を教えてくれるgem、Bullet を使っている人は多いと思います。

最近では Rails では API サーバのみを作り、フロントエンドは JS フレームワークやスマホアプリで実装というケースが増えてきました。
こういったプロジェクトでは Rails で画面をまったく作らないので、画面があること前提の開発支援系 gem を使えなくて困ったりします。
そこで bullet に関してはテスト環境で動作させるようにしました。

bullet のテスト環境設定

とっても簡単です。

config/environments/test.rb
config.after_initialize do
  Bullet.enable = true
  Bullet.bullet_logger = true
  Bullet.raise = false # raise an error if n+1 query occurs
end
spec/spec_helper.rb
if Bullet.enable?
  config.before(:each) do
    Bullet.start_request
  end

  config.after(:each) do
    Bullet.perform_out_of_channel_notifications if Bullet.notification?
    Bullet.end_request
  end
end

これだけ。

bullet の警告の確認

bullet を通常の画面の存在する Web アプリで実行した場合は、画面表示時に Javascript の alert ダイアログが表示されるという、非常にウザい 分かりやすい通知方法になっていると思います。
API サーバでは画面がないのでそういった確認方法は使えないので、代わりにログを吐く設定をテスト環境で行っています。
bullet のログは log/bullet.log に吐かれますので、テスト実行時に tail するなりしておくと良いかもしれません。
後述していますが、N+1 問題警告時にテストが落ちるように設定することもできます。

解説のようなもの。

公式の bullet#Run-in-tests に書いてる内容ほぼそのままです。
ただしあちらの内容だと Bullet.raise = true に設定されており、N+1 問題のあるクエリが実行されると軒並みテストが落ちるようになるので、若干鬼設定かなあと false に変えています。
より確実に bullet の警告に気づくようにしたいのであれば、公式と同じくここを true にしておくと良いです。

実際にはこの手のテストの設定は rails_helper.rb に書いてる人も多いでしょうから、こんな風になることの方が多いかもしれません。

spec/rails_helper.rb
  :
RSpec.configure do |config|
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.use_transactional_fixtures = false
  config.order = 'random'
  config.include FactoryGirl::Syntax::Methods
  :

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
    FactoryGirl.reload
    DatabaseCleaner.start
    # ↓ココ
    Bullet.start_request if Bullet.enable?
  end

  config.after(:each) do
    DatabaseCleaner.clean
    # ↓ココから
    if Bullet.enable?
      Bullet.perform_out_of_channel_notifications if Bullet.notification?
      Bullet.end_request
    end
    # ↑ココまで
  end
end

bullet 用に処理部分を追加する必要はないので、config.before(:each)config.after(:each) の、DatabaseCleaner や DatabaseRewinder の呼び出しを行っているだろう当たりに適当に突っ込んでおけば動きます。
と、Rspec 前提で書いてますが他のテスティングフレームワークだとどうなるのか良く分かりません。
公式に書かれているように Bullet の開始と終了処理を、個々の example 実行の前後で呼び出してあげると動くと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away