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

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

---

RailsのController TestでWeb APIのテストをするときにハマったシリーズその②．

その①はこちら（[【Rails】RSpecでWeb APIのテストでハマったところ①](http://qiita.com/izumin5210/items/e27ab2987683084fb009)）．

# ハマったところ
## そもそもどうやって中身をテストしようか…
『[Everyday Rails - RSpecによるRailsテスト入門](https://leanpub.com/everydayrailsrspec-jp)』訳者の[@jnchito](https://twitter.com/jnchito)さんが[すばらしいgem](https://github.com/collectiveidea/json_spec)を教えて下さいました．

<blockquote class="twitter-tweet" lang="en"><p><a href="https://twitter.com/izumin5210">@izumin5210</a> ちなみに僕はjson_specっていうgemを使っています。最初は慣れるまでちょっと時間がかかったけど、コツをつかめばなかなか便利なツールです。 <a href="https://t.co/cVrDHrmhgl">https://t.co/cVrDHrmhgl</a></p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/statuses/448193107306106881">March 24, 2014</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

ということで[json_spec](https://github.com/collectiveidea/json_spec)を使っていこうとしたのですが，超クセが強くていっぱいハマりました．

## json_specで文字列の比較ができない
### 内容

`Lecture`というmodelの指定した`id`要素を取ってくる`LecturesController#show`のレスポンスのテストしようと以下のようなspecを記述．

```ruby:spec/requests/lectures_spec.rb
describe 'GET /api/v1/lectures/:id' do
  let(:lecture) { FactoryGirl.create(:lecture) }
  before(:each) { get :show, lecture: lecture }

  it 'returns lecture json' do
    expect(response.body).to have_json_path('lecture')
    expect(response.body).to be_json_eql(lecture.id).at_path('lecture/id')
    expect(response.body).to be_json_eql(lecture.title).at_path('lecture/title')
  end
end
```

期待してるレスポンスはこんな感じ．

```
{
  "lecture": {
    "id": 1,
    "title": "プログラミングI"
  }
}
```

しかしエラーが出る（`MultiJson::ParseError`）．

>
> Failures:
> 
>   1) Lectures GET /lectures/:id returns lecture json
>      Failure/Error: expect(response.body).to be_json_eql(lecture.title).at_path('lecture/title')
>      MultiJson::ParseError:
>        795: unexpected token at ...（略）
>

### 原因・対策

`be_json_eql`にそのまま文字列を渡したらダメっぽい？
こんな感じでダブルクォートをつけてあげないといけない．

```ruby:spec/requests/lectures_spec.rb
expect("\"#{response.body}\"").to be_json_eql(lecture.title).at_path('lecture/title')
```


## FactoryGirlがツンデレ


### 内容

よくわからんけど`FactoryGirl.create()`でnilが返ってきてた．しかしエラーは出ていない．何故．

（lecture has many timetablesです）

```ruby:spec/factories/lectures.rb
FactoryGirl.define do
  factory :lecture do
    title { Faker::Lorem.word }
    after(:build) do |lecture, evaluator|
      create_list(:timetable, evaluator.timetables_count, lecture: lecture)
    end
  end
end
```

### 原因・対策

なにをしても改善されないので試しに[database_cleaner](https://github.com/bmabey/database_cleaner)を導入してみる．

```ruby:spec_helper.rb
config.before(:suite) do
  begin
    DatabaseCleaner.start
  ensure
    DatabaseCleaner.clean
  end
end
```

**何故かテストがとおった**

#### 考察
`lecture`と`has_many`になってる`timetable`のfactoryがバリデーションに引っかかって落ちてたような気がする．
テスト用DBがうまいこと初期化されてなくてそんなことになってたのかなーと考察．

---


ちょっと適当にだらだら書いてしまっただけになってるので，「RSpecで書くWeb APIのテストまとめ」みたいな記事が必要かもしれない（自分のためにも）．


# 参考
- [**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)
- [collectiveidea/json_spec](https://github.com/collectiveidea/json_spec)
- [bmabey/database_cleaner](https://github.com/bmabey/database_cleaner)
- [factory_girl/GETTING_STARTED.md at master · thoughtbot/factory_girl](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md)