(2014/12/12 追記)
本稿のアップデート版みたいなのをアップしました→『【Rails】RSpecと三種の神器でらくちんWeb APIテスト - Qiita』
Railsアプリを作るときに,Web APIのテストをしようとしたら命を落としかけたのでいろいろヤバそうなところをメモっておきますφ(`д´)
JSONレスポンスのテストはすべき?
**Everyday Rails - RSpecによるRailsテスト入門**では,Viewのテストは取り扱っていません(理由は2章 Q&Aにて).
でもWeb APIのレスポンスはどうなんだろう? ということで訳者のひとりである西脇.rbの@jnchitoさんに聞いてみたところ,次のように答えていただきました.
@izumin5210 するべきかどうかはケースバイケースです・・・っていうと回答にならないので、yes/noで答えるならyesかな~。というのも画面に比べて、APIは問題の発生に気付きにくい&手作業+目視での確認が面倒なので、RSpecで品質を担保させた方が効率的だから。
— Junichi Ito (伊藤淳一) (@jnchito) March 24, 2014
ということで実際にテストを書いていったのですが,たくさんハマったところがあったので共有しておきます.
追記(2014/3/27)
最初はController SpecにJSONのテストを書いていたのですが,Rails API Testing Best Practices With RSpecによると
Use RSpec Request Specs
Since we’ve established that we’ll be using Rack::Test to drive the tests, RSpec request specs make the most sense. There’s no need to get fancy and add extra weight to your testing tools for this.
Request specs provide a thin wrapper around Rails’ integration tests, and are designed to drive behavior through the full stack, including routing (provided by Rails) and without stubbing (that’s up to you).
To test requests and their responses, just add a new request spec. I’ll demonstrate testing a user sessions endpoint. My API returns a token on a successful login.
だそうですので,Request Specで書きなおしました.
JSONレスポンスのテストはRequest Specで書いて,ステータスコードとかのテストをController Specに書けばいいのかな…?
ハマったところ
JSONが返ってこない(missing template編)
内容
とりあえずresponse.body
のテストをしようとしたところ,まさかのActionView::MissingTemplate
が発生….
半日ほど時間を溶かしました.
問題のコードは以下(抜粋).
describe 'GET #show' do
it 'returns valid response body' do
get :show, id: @test
expect(response.body).to # ...(略)
end
end
原因・対策
HTTPヘッダにAccept
を設定してなかったのが原因.当然の結果だった.
# 以下の行でAcceptを設定
before(:each) { request.env["HTTP_ACCEPT"] = 'application/json' }
describe 'GET #show' do
it 'returns valid response body' do
get :show, id: @test
expect(response.body).to # ...(略)
end
end
追記(2014/3/27)
上記の問題はController Specで発生するが,Request Specでは発生しないみたい.
JSONが返ってこない(なぜか空っぽになってる編)
内容
よし!これでJSONが返ってくるぞ!
…と思いきやどうやってもテストに失敗する.
puts request.body
してみると
{}
レスポンスボディがからっぽになっている.
どうもJSONの中身がちゃんとレンダリングされてない.
原因・対策
これはJSONのレンダリングに使ってるjbuilder
というgemが原因らしい.
spec_helper.rb
に1行足して問題解決.
RSpec.configure do |config|
# 以下の行を追加
config.render_views = true
end
追記(2014/3/27)
これも同様に,上記の問題はController Specで発生するが、Request Specでは発生しないみたい.
まだまだあるけどつづきはまた今度…
参考
- Everyday Rails - RSpecによるRailsテスト入門(超おすすめ)
- The RSpec Book (Professional Ruby Series)
- Rails でつくる API のテストの書き方(RSpec + FactoryGirl) - 彼女からは、おいちゃんと呼ばれています
- ruby on rails - Set Rspec default GET request format to JSON - Stack Overflow
- ruby on rails - Why is JBuilder not returning a response body in JSON when testing RSPEC - Stack Overflow
- Rails API Testing Best Practices With RSpec