LoginSignup
4
2

More than 3 years have passed since last update.

【RSpec】shared_contextを使ってレスポンスチェックを共通化する

Last updated at Posted at 2019-07-26

動作検証環境

  • Rails 5.2.3
  • rspec-rails 3.8.2

shared_context 作成

  • ポイント
    • テスト本体でsubject (ここでは send_request)を使うため、expectの前にsend_requestを呼ぶ。
    • 順序が不定な場合は、json_expressionsmatch_json_expressionを使う。
spec/support/shared_context_for_api.rb
RSpec.shared_context 'api' do
  shared_examples 'http_status_code_200' do
    it 'returns 200' do
      send_request

      expect(response).to be_successful
      expect(response.status).to eq(200)
      # または以下。お好みで。
      # expect(response).to have_http_status(:ok)
    end
  end

  shared_examples 'http_status_code_200_with_json' do
    it 'returns 200 with JSON' do
      send_request

      expect(response).to be_successful
      expect(response.status).to eq(200)
      expect(JSON.parse(response.body).deep_symbolize_keys).to eq(expected_response)
    end
  end

  shared_examples 'http_status_code_200_with_json_expression' do
    it 'returns 200 with JSON' do
      send_request

      expect(response).to be_successful
      expect(response.status).to eq(200)
      expect(response.body).to match_json_expression(expected_response)
    end
  end

  shared_examples 'http_status_code_404' do
    it 'returns 404' do
      send_request

      expect(response).to_not be_successful
      expect(response.status).to eq(404)
      # または以下。お好みで。
      # expect(response).to have_http_status(:not_found)
    end
  end

  shared_examples 'http_status_code_500' do
    it 'returns 500' do
      send_request

      expect(response).to_not be_successful
      expect(response.status).to eq(500)
    end
  end
end

shared_context 利用

  • ポイント
    • include_context 'api'
    • it_behaves_like 'http_status_code_200''http_status_code_200' に ↑のshared_examples で定義したものを指定する)
spec/requests/users_spec.rb
RSpec.describe Api::V1::UsersController, type: :request do
  include_context 'api'

  describe 'GET /api/v1/users' do
    context 'without params' do
      subject(:send_request) { get '/api/v1/users' }

      let(:expected_response) { ... }

      before { create_list(:user, 2) }

      it_behaves_like 'http_status_code_200_with_json'
    end
  end

  describe 'GET /api/v1/users/:email' do
    context 'when the user exists' do
      subject(:send_request) { get "/api/v1/users/#{@user.id}" }

      let(:expected_response) { ... }

      before { @user = create(:user) }

      it_behaves_like 'http_status_code_200_with_json'
    end

    context 'when the user does not exist' do
      subject(:send_request) { get '/api/v1/users/non_existing_user_id' }

      it_behaves_like 'http_status_code_404'
    end
  end
end

expected_responseとしてJSONを使うパターン

  describe 'GET /api/v1/endpoint' do
    context 'with valid request' do
      subject(:send_request) { get '/api/v1/endpoint' }

      let(:expected_response) do
        JSON.parse(file_fixture('endpoint_response_index.json').read, symbolize_names: true)
      end

      it_behaves_like 'http_status_code_200_with_json_expression'
    end
  end

subjectを使わずbeforeだけで書く

  • この場合、shared_contextの先頭で、毎回send_request (= subject)を呼ぶ必要はない。
RSpec.describe Api::V1::UsersController, type: :request do
  include_context 'api'

  describe 'GET /api/v1/users' do
    context 'without params' do
      let(:expected_response) { ... }

      before do
        create_list(:user, 2)
        get '/api/v1/users'
      end

      it_behaves_like 'http_status_code_200_with_json'
    end
  end
end
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2