地方でリモートワーク

プログラミング、先物、fx,仮想通貨なんでもやります

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