【Rails】RSpecでWeb APIのテストでハマったところ①

（2014/12/12 追記）
本稿のアップデート版みたいなのをアップしました→『[【Rails】RSpecと三種の神器でらくちんWeb APIテスト - Qiita](http://qiita.com/izumin5210/items/de614b5b5b2c44486e87)』

---
Railsアプリを作るときに，Web APIのテストをしようとしたら命を落としかけたのでいろいろヤバそうなところをメモっておきますφ(｀д´)

# JSONレスポンスのテストはすべき？

**[Everyday Rails - RSpecによるRailsテスト入門](https://leanpub.com/everydayrailsrspec-jp)**では，Viewのテストは取り扱っていません（理由は[2章 Q&Aにて](https://twitter.com/jnchito/status/447914738882588672)）．

でもWeb APIのレスポンスはどうなんだろう？ ということで訳者のひとりである[西脇.rb](http://nishiwaki-higashinadarb.doorkeeper.jp/)の[@jnchito](https://twitter.com/jnchito)さんに聞いてみたところ，次のように答えていただきました．

<blockquote class="twitter-tweet" lang="en"><p><a href="https://twitter.com/izumin5210">@izumin5210</a> するべきかどうかはケースバイケースです・・・っていうと回答にならないので、yes/noで答えるならyesかな～。というのも画面に比べて、APIは問題の発生に気付きにくい＆手作業+目視での確認が面倒なので、RSpecで品質を担保させた方が効率的だから。</p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/statuses/448192723736997888">March 24, 2014</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

ということで実際にテストを書いていったのですが，たくさんハマったところがあったので共有しておきます．

## 追記（2014/3/27）
最初はController SpecにJSONのテストを書いていたのですが，[Rails API Testing Best Practices With RSpec](http://matthewlehner.net/rails-api-testing-guidelines/)によると

> 
> ### 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`が発生…．
半日ほど時間を溶かしました．

問題のコードは以下（抜粋）．

```ruby:test_controller_spec.rb
describe 'GET #show' do
  it 'returns valid response body' do
    get :show, id: @test
    expect(response.body).to # ...(略)
  end
end
```

### 原因・対策
HTTPヘッダに`Accept`を設定してなかったのが原因．当然の結果だった．

```ruby:test_controller_spec.rb
# 以下の行で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行足して問題解決．

```spec_helper.rb
RSpec.configure do |config|
  # 以下の行を追加
  config.render_views = true
end
```

### 追記（2014/3/27）
これも同様に，上記の問題はController Specで発生するが、Request Specでは発生しないみたい．


---

まだまだあるけどつづきはまた今度…

# 参考
- [**Everyday Rails - RSpecによるRailsテスト入門**](https://leanpub.com/everydayrailsrspec-jp)（超おすすめ）
- [The RSpec Book (Professional Ruby Series)](http://www.amazon.co.jp/gp/product/4798121932/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=4798121932&linkCode=as2&tag=masayuki5210-22)
- [Rails でつくる API のテストの書き方（RSpec + FactoryGirl） - 彼女からは、おいちゃんと呼ばれています](http://blog.inouetakuya.info/entry/2013/10/27/200111)
- [ruby on rails - Set Rspec default GET request format to JSON - Stack Overflow](http://stackoverflow.com/questions/11022839/set-rspec-default-get-request-format-to-json)
- [ruby on rails - Why is JBuilder not returning a response body in JSON when testing RSPEC - Stack Overflow](http://stackoverflow.com/questions/9965945/why-is-jbuilder-not-returning-a-response-body-in-json-when-testing-rspec)
- [Rails API Testing Best Practices With RSpec](http://matthewlehner.net/rails-api-testing-guidelines/)