(2014/12/12 追記)
本稿のアップデート版みたいなのをアップしました→『【Rails】RSpecと三種の神器でらくちんWeb APIテスト - Qiita』
RailsのController TestでWeb APIのテストをするときにハマったシリーズその②.
その①はこちら(【Rails】RSpecでWeb APIのテストでハマったところ①).
ハマったところ
そもそもどうやって中身をテストしようか…
『Everyday Rails - RSpecによるRailsテスト入門』訳者の@jnchitoさんがすばらしいgemを教えて下さいました.
@izumin5210 ちなみに僕はjson_specっていうgemを使っています。最初は慣れるまでちょっと時間がかかったけど、コツをつかめばなかなか便利なツールです。 https://t.co/cVrDHrmhgl
— Junichi Ito (伊藤淳一) (@jnchito) March 24, 2014
ということでjson_specを使っていこうとしたのですが,超クセが強くていっぱいハマりました.
json_specで文字列の比較ができない
内容
Lecture
というmodelの指定したid
要素を取ってくるLecturesController#show
のレスポンスのテストしようと以下のようなspecを記述.
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:
- 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
にそのまま文字列を渡したらダメっぽい?
こんな感じでダブルクォートをつけてあげないといけない.
expect("\"#{response.body}\"").to be_json_eql(lecture.title).at_path('lecture/title')
FactoryGirlがツンデレ
内容
よくわからんけどFactoryGirl.create()
でnilが返ってきてた.しかしエラーは出ていない.何故.
(lecture has many timetablesです)
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を導入してみる.
config.before(:suite) do
begin
DatabaseCleaner.start
ensure
DatabaseCleaner.clean
end
end
何故かテストがとおった
考察
lecture
とhas_many
になってるtimetable
のfactoryがバリデーションに引っかかって落ちてたような気がする.
テスト用DBがうまいこと初期化されてなくてそんなことになってたのかなーと考察.
ちょっと適当にだらだら書いてしまっただけになってるので,「RSpecで書くWeb APIのテストまとめ」みたいな記事が必要かもしれない(自分のためにも).