【Rails/RSpec】better_errors gemをテスト環境で有効にしていたらハマった

better_errorsは、Railsのデフォルトエラーページよりもエラーを詳細に表示し、デバッグを助けてくれるgemです。

github.com

READMEにある通り、基本的にはdevelopment環境での使用が想定されています。
しかしながら、今回、test環境で有効にしていたことによりハマったことがあったので、記録として残しておきます。

何が起きたか

テストを書いていたら、以下の状況になりました。

「例外を起こすことのテストで、RSpec実際に例外が発生しているはずなのにraise_errorするとテストが失敗するぞ?

↓実際に書いたテストを簡略化したもの

it do
  expect { get root_path }.to raise_error RuntimeError # root_pathにアクセスすると例外が発生するようにしているので、それを確認するテスト
end

↓結果

Failure/Error: expect { get root_path }.to raise_error RuntimeError
       expected RuntimeError but nothing was raised

画面上でアクセスしても例外が発生するのに、テストすると「例外なんて発生していないよ」と言われ、結構混乱しました。

原因: better_errorsがテスト環境にインストールされていた

色々試行錯誤する中で、悪さをしているライブラリがないかとGemfileを見ると、あることに気づきました。

group :development, :test do
  gem 'better_errors'
end

あれ、better_errorsってテスト環境で有効にしなくても良いものでは?と思い、とりあえず消してみました。

↓修正後のGemfile

group :development do
  gem 'better_errors'
end

結果、、、

Finished in 0.02689 seconds (files took 1.18 seconds to load)
1 example, 0 failures

これかー!

better_errorsをtest環境で有効にしてしまっていたのが原因とわかりました。 では、具体的に、なぜbetter_errorsをテスト環境に入れていると例外が捕捉できないのでしょうか?

better_errorsは例外をrescueする

better_errorsのコードを読んだら、例外をrescueして、カスタマイズしたエラー画面を表示していました。 そして例外はそのまま伝播させず、500のレスポンスとして返すようにしていました。

better_errors/middleware.rb

def protected_app_call(env)
  @app.call env
rescue Exception => ex
  @error_page = @handler.new ex, env
  log_exception
  show_error_page(env, ex)
end

def show_error_page(env, exception=nil)
  # ...(略)
  [status_code, headers, [content]]
end

だからRSpec側でraise_error XXXしても、例外は発生していない、と言われたんですね。

さいごに

しばらく、better_errorsというところに当たりをつけられず解決まで少し時間を要しましたが、原因がわかってスッキリしました。
このリポジトリbetter_errorsを導入したのは私ではないのですが、おそらくsystem specの失敗時のスクリーンショットからデバッグをしやすくするために入れたのかなーと推測しています。

実はこれ以外にもbetter_errorsによって想定と違う動きをした、という例があるのでまた記事にして残しておきたいと思います。