LoginSignup
3
2

More than 5 years have passed since last update.

Rspec APIのspecを見やすくする"shared_context"

Posted at

社内でよくRailsでAPIを書くことが多く、そのテストをするときによく使うAPI用のshared_contextを紹介します。

ApiHepers

以下がshared_context本体となります。
spec/support/api_helpers.rbとして作成します。

spec/support/api_helpers.rb
module ApiHelpers
  shared_context 'api helper', type: :api do
    subject { call_api }

    let(:path) { nil }
    let(:method) { nil }
    let(:body) { nil }
    let(:header) { nil }
    let(:default_header) do
      {
        'Content-Type' => 'application/json'
      }
    end

    let(:call_api) do
      before_call_api if respond_to?(:before_call_api)

      body_json = body ? body.to_json : nil
      merged_header = default_header.merge(header.to_h)
      send(method.to_s.downcase, path, body_json, merged_header)

      after_call_api if respond_to?(:after_call_api)
    end
  end
end

そして、rails_helperに以下を記載し、作成したmoduleを読み込ませるます。

spec/rails_helpers.rb

# supportが読み込みがコメントアウトされてないか確認
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 

RSpec.configure do |config|

  # 追加するmodule
  config.include ApiHelpers
end

解説

APIの呼び出しの根幹部分はこちらの、call_apiになっています。
処理の仕組みは簡単で、methodに指定した文字列を小文字化 => シンボルに変えて、requestのspecのメソッドとして呼び出しています。

    let(:call_api) do
      before_call_api if respond_to?(:before_call_api)

      body_json = body ? body.to_json : nil
      send(method.to_s.downcase.to_sym, path, body_json, default_header.merge(header.to_h))

      after_call_api if respond_to?(:after_call_api)
    end

そしてこのcall_apiは、基本subjectを呼ぶことで呼ばれるようになっています。

    subject { call_api }

また、PUTやPATCHのようにAPIを読んだ後に特定のオブジェクトを更新したい場合のために、after_call_apiというメソッドをcall_apiの後で呼び出すようにしています。

使用例

RSpec.describe API::V1::Sessions do
  describe 'POST /api/v1/sign_in', type: :api do
    let(:path) { '/api/v1/sign_in' }
    let(:method) { 'POST' }
    let(:body) do
      {
        email: 'hoge@example.com',
        password: 'password'
      }
    end

    let(:after_call_api) { user.reload }

    let(:user) do
      user = FactoryGirl.create(:user, email: 'hoge@example.com')
      user.set_password_with_encrypt('password')
      user.save
      user
    end


    it do
      subject
      expect(response.status).to eq(201)

      json = JSON.parse(response.body)
      expect(json[:id]).to eq(user.id)
      expect(json[:access_token]).to eq(user.session.access_token)
    end

    it { expect { subject }.to change(Session, :count).by(1) }
end

重要な部分としては、

describe 'POST /api/v1/sign_in', type: :api do

の部分。
ここのtype: :apiを指定することでAPIのshared_contextを呼び出しています。

3
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
3
2