LoginSignup
21
19

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-01-18

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 実行の前後で呼び出してあげると動くと思います。

21
19
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
21
19