2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RSpecの基本のキホン!(リクエストスペック編)

2
Posted at

リクエストスペック

リクエストスペックとは

リクエストスペックは、Rails アプリケーションで作成されたバックエンド API の動作を検証するための統合テスト。
システムスペックと同様、アプリケーションの動作をテストするためには単体テストであるコントローラスペックよりもこちらが推奨される。

リクエストスペックの作成

作成コマンド
$ rails g rspec:request projects_api
初期状態のspec/requests/projects_apis_spec.rb

require 'rails_helper'

RSpec.describe "ProjectsApis", type: :request do
  describe "GET /projects_apis" do
    it "works! (now write some real specs)" do
      get projects_apis_path
      expect(response).to have_http_status(200)
    end
  end
end

デフォルトだと、RSpec はファイル名を複数形にするので、projects_apis というファイル名になる。
リネームし、リクエストスペックらしい書き方でテストを追加すると以下のようになる。

spec/requests/projects_api_spec.rb
require 'rails_helper'

RSpec.describe "ProjectsApis", type: :request do
  # 1件のプロジェクトを読み出すこと
  it 'loads a project' do
    user = FactoryBot.create(:user)
    FactoryBot.create(:project, name: "Sample Project")
    FactoryBot.create(:project, name: "Second Sample Project", owner: user)

    get api_projects_path, params: { # 好きなルーティング名を指定できる
      user_email: user.email,
      user_token: user.authentication_token
    }

    expect(response).to have_http_status(:success)
    json = JSON.parse(response.body)
    expect(json.length).to eq 1
    project_id = json[0]["id"]

    get api_project_path(project_id), params: {
        user_email: user.email,
        user_token: user.authentication_token
    }

    expect(response).to have_http_status(:success)
    json = JSON.parse(response.body)
    expect(json["name"]).to eq "Second Sample Project"
    # などなど
  end

  # プロジェクトを作成できること
  it 'creates a project' do
    user = FactoryBot.create(:user)
    project_attributes = FactoryBot.attributes_for(:project)
    expect {
      post api_projects_path, params: {
        user_email: user.email,
        user_token: user.authentication_token,
        project: project_attributes
      }
    }.to change(user.projects, :count).by(1)
    expect(response).to have_http_status(:success)
  end
end

コントローラスペックとの相違点

コントローラスペックと違い、好きなルーティング名を指定できる(つまりアクション名に依存せずコントローラとは結びつかない)ので、テストしたいルーティング名を指定できているか確認する必要がある。

API 以外のコントローラのテストをリクエストスペックで書く

API 以外のコントローラのテストをリクエストスペックで書くこともできる。

require 'rails_helper'

RSpec.describe "Projects", type: :request do
  # 認証済みのユーザーとして
  context "as an authenticated user" do
    before do
      @user = FactoryBot.create(:user)
    end

    # 有効な属性値の場合
    context "with valid attributes" do
    # プロジェクトを追加できること
      it "adds a project" do
        project_params = FactoryBot.attributes_for(:project)
        sign_in @user
        expect {
          post projects_path, params: { project: project_params }
        }.to change(@user.projects, :count).by(1)
      end
    end

    # 無効な属性値の場合
    context "with invalid attributes" do
      # プロジェクトを追加できないこと
      it "does not add a project" do
        project_params = FactoryBot.attributes_for(:project, :invalid)
        sign_in @user
        expect {
          post projects_path, params: { project: project_params }
        }.to_not change(@user.projects, :count)
      end
    end
  end
end

また、コントローラが標準的なメールアドレスとパスワードの認証システムを使っている場合、上記のテストを機能させるにはDeviseのsign_inヘルパーをリクエストスペックに追加する必要がある。

spec/support/request_spec_helper.rb
module RequestSpecHelper
  include Warden::Test::Helpers

  def self.included(base)
    base.before(:each) { Warden.test_mode! }
    base.after(:each) { Warden.test_reset! }
  end

  def sign_in(resource)
    login_as(resource, scope: warden_scope(resource))
  end

  def sign_out(resource)
    logout(warden_scope(resource))
  end

  private

  def warden_scope(resource)
    resource.class.name.underscore.to_sym
  end
end
spec/rails_helper.rb
RSpec.configure do |config|
  config.include RequestSpecHelper, type: :request
end

参考文献

この記事は以下の情報を参考にして執筆しました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?