RspecでJSONオブジェクトの値を確認する
こんにちは、皆さん!
Railsでウェブアプリケーションを作っていく上で、その品質を保証するためにRspecは欠かせない。そして、最近ではRailsでAPIを作る人たちも増えてきている。そんなAPIなのだが、普通コントローラーがJSONオブジェクトという形でデータを返してくる。今回はそのオブジェクト内の値をチェックする方法を紹介したいと思う。
- トピック:
今回使うモデルの説明
create
アクション。
# users_controller.rb def create @user = User.create(user_params) render json: @user, status: :created end private def user_params params.require(:user).permit(:email, :password, :password_confirmation) end
ベースのテストコードは下記のようになっている。今回はここにもう一つコードを足して、JSONとして返ってきたオブジェクトのメールがもともと入れたメールと同じか確認する。
# users_controller_spec.rb describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) end end
覚えておくべきことは
- ここで使うのは
create
アクションだけであること - そのアクションではJSONオブジェクトのUserが返され、
:created
というステータスがついてくること - そのステータスはテストコードの
POST
リクエスト後に確認がされていること response.body
に返されたJSONオブジェクトの詳細が入っていること
では、実際に両方の例を見ていこう!!
うまくいかない例
describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) expect(response.body['email']).to eq("example@example.com") end end
これはいつもJavaScriptでキーを使って値を抜き出してる人からしたら、とても常識的なやり方。しかし、Rubyでは下記のように想定外のことがおこり、テストが下記のようにフェイルしてしまう。
1) V1::UsersController POST create should create a user with valid params Failure/Error: expect(response.body['email']).to eq("example@example.com") expected: "example@example.com" got: "email" (compared using ==) # ./spec/controllers/users_controller_spec.rb:16:in `block (3 levels) in <top (required)>'
これはつまり何かというと、response.body['email']
の結果がemail
になっているのだ。
試しにputs response.body
でresponse.body
の内容をアウトプットしてみた。そしたら下記の結果が得られた。
{"id":841425152,"email":"example@example.com","created_at":"2018-12-30T19:26:45.289Z","updated_at":"2018-12-30T19:26:45.289Z"}
これって当たり前だけど、JavaScriptのキーと値のペア式になっているのだ。でも、これこそが問題の原因。なぜなら、Rubyでのキーと値のペア式はJavaScriptのそれとは違うからだ。皆さんもご存知かと思うが、下記のようなシンタックスがRubyのやり方。
{"id"=>841425155, "email"=>"example@example.com", "created_at"=>"2018-12-30T23:07:17.457Z", "updated_at"=>"2018-12-30T23:07:17.457Z"}
そう、=>
のような矢印でシンボルを表現するやり方だ。では、次にどうやったらRubyのわかる形に変更できるかについて見ていこう!!
うまくいく例
JSON.parsse()
これは単純にJSONオブジェクトをRubyのわかるものに変えるだけなのだ。言うなら、to_json()
関数の逆をやっているのだ。
よって、先ほど、puts response.body
でJavaScriptの形になっていたものはputs JSON.parse(response.body)
と改めることで下記のようになる。
{"id"=>841425155, "email"=>"example@example.com", "created_at"=>"2018-12-30T23:07:17.457Z", "updated_at"=>"2018-12-30T23:07:17.457Z"}
つまり、うまくいくRspecのコードは下記のようになる。
describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) expect(JSON.parse(response.body)['email']).to eq("example@example.com") end end
まとめ
このように問題を発見することができれば、あとはしっかりとしたRubyの知識があればこのような問題は解決できる。なので、何かエラーに面したときはいろいろとプリントアウトしてみて、手掛かりを探しましょう!!
皆さんのテストコードがより素晴らしいものになることを祈ります。
ご精読ありがとうございました。では、また次回まで✌