JSONのPOSTリクエストとRspecでテストする方法

RspecでAPIのテストする方法です。今回はPOSTリクエストです。

完成コード

まずは完成コードから掲載したいと思います。

spec/requests/api/vi/user_spec.rb

require 'rails_helper'
RSpec.describe 'ユーザー新規作成API', type: :request do
describe 'POST /api/v1/users/create.json' do
let(:request_header) do
{ 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
end
let(:user) do
'{"name": "testuser",
          "profile": "testuser",
          "email": "user1@test.com",
          "password": "testtesttest",
          "password_confirmation": "testtesttest"}'
end
subject do
post api_v1_users_create_path(format: :json), user, request_header
end
context "正常系" do
it "ユーザーが作成される" do
expect { subject }.to change(User, :count).by(1)
end
it "200を返す" do
subject
expect(response).to be_success
end
it "JSONに含まれるキーが適切である" do
subject
result = JSON.parse(response.body)
expect(result).to have_key('result')
expect(result).to have_key('message')
expect(result).to have_key('error_code')
end
end
context "異常系" do
context "すでにユーザーが存在する" do
before do
create(:user, email: "user1@test.com")
end
it "エラーが返ってくる" do
subject
body = JSON.parse(response.body)
expect(body["result"]).to eq false
expect(body["message"]).to eq ["メールアドレスはすでに存在します"]
expect(body["error_code"]).to eq 3
end
end
context "メール、パスワードが未記入" do
let(:valid_user) do
'{"name": "testuser",
              "profile": "testuser",
              "email": "",
              "password": "",
              "password_confirmation": "testtesttest"}'
end
before do
post api_v1_users_create_path(format: :json), valid_user, request_header
end
it "エラーが返ってくる" do
body = JSON.parse(response.body)
expect(body["result"]).to eq false
expect(body["message"]).to include "メールアドレスを入力してください"
expect(body["message"]).to include "パスワードを入力してください"
expect(body["error_code"]).to eq 3
end
end
end
end
end

解説

requestsで作成する

controller specではなく、request specで作成する方法が一般的のようです。

request_headerを定義する

request_headerをletで定義してpostする際に使う必要があります。

request spec – Request specs – RSpec Rails – RSpec – Relish

FactoryGirlを使わない

はじめはFactoryGirlのattributes_forメソッドでJSONテストデータを作成していましたが、うまくいきませんでした。そのためべた打ちしてます。

RailsはデフォルトでJSONをwrapしてくれる

今回の場合,

 let(:user) { {user: FactoryGirl.attributes_for(:user) }}

のようにuserでwrapしてあげるとFactoryGirlを使ってもうまくいきます。
しかし、今回はwrapせずともPOSTリクエストを受け付けることを検証したかったため、べた打ちでテストデータを書きました。
テストデータはuserでwrapされていませんが、実際は

{"user":
{"name": "hoge",
"profile": "test",
"email": "hoge@gehoff.com",
"password": "testtesttest",
"password_confirmation": "testtesttest",
"sex": "male",
"birth_date": "2000-01-01 00:00:00",
"agreement": "1",
"telephone_number": "000-1111-2222",
"address1": "住所1",
"address2": "住所2",
"status": "active",
"pay_type":  "CreditCard"}}

のようにuserでwarpしてくれます。

そのコードはconfig/initializers/wrap_parameters.rbに定義されています。

# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
#  self.include_root_in_json = true
# end

これでcontroller名に沿ってparameterをwrapしてくれます。

controller名に沿っていない場合はcontrollerで定義する必要があります。
今回私の場合もdeviseを使っていてcontroller名に沿っていないため、別途定義しました。

app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
wrap_parameters :user, format: [:json]

keyのテスト

expect(result).to have_key('result')でPOSTリクエストに対するレスポンスパラメータのkeyをテストすることができます。
今回はjbuilderで定義しました。

errorコードのテスト

エラーコードもcontrollerとjbuilderで定義するとテストできます。

special thanks

RSpecでJSONによるPOSTリクエストをテスト | EasyRamble

パーフェクトRuby on Rails

パーフェクトRuby on Rails

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA