RSpecでコメント機能のAPIテストを実装 Rails

プログラミング
スポンサーリンク

概要

RSpecを使いコメント機能のAPIテストを実装

.

対応するコントローラーとルーティングはこちら

.

コメントモデルのテストはこちら
.

【 使用gem】
・ gem "factory_bot_rails"
テストデータの作成を手伝ってくれるGemです。
・ gem "faker"
ダミーデータを作成するgem
・ gem "rspec-rails"
rspecをrails用にカスタマイズしたgem

完成形

comments_controllerに対するテスト
.

spec/v1/requests/articles/comments_spec.rb

require "rails_helper"

RSpec.describe "V1::Articles::Comments", type: :request do
  describe "POST /v1/articles/:article_id/comments" do
    subject { post(v1_article_comments_path(article), params: params, headers: headers) }

    context "ユーザーがログインしていて" do
      let(:current_user) { create(:user) }
      let(:headers) { current_user.create_new_auth_token }

      context "コメント対象の記事が存在する時" do
        let(:article) { create(:article) }
        let(:params) { { comment: attributes_for(:comment, article_id: article.id) } }

        it "コメントができる" do
          expect { subject }.to change { current_user.comments.count }.by(1)
          expect(response).to have_http_status(:ok)
          res = JSON.parse(response.body)
          expect(res["content"]).to eq params[:comment][:content]
        end
      end
    end
  end

  describe "GET /v1/articles/:article_id/comments" do
    subject { get(v1_article_comments_path(article)) }

    context "任意の記事に" do
      let(:article) { create(:article) }
      let(:article_id) { article.id }

      context "コメントがある時" do
        let!(:comment) { create_list(:comment, 3, article_id: article.id) }
        it "コメントの一覧が取得できる" do
          subject
          res = JSON.parse(response.body)
          expect(res.length).to eq 3
          expect(res[0].keys).to eq ["id", "content", "user_id", "article_id", "created_at", "updated_at"]
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

  describe "/v1/articles/:article_id/comments/:id" do
    subject { get(v1_article_comment_path(article, comment_id)) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "指定したコメントがある場合" do
        let(:comment) { create(:comment) }
        let(:comment_id) { comment.id }

        it "コメントの詳細が見れる" do
          subject
          res = JSON.parse(response.body)
          expect(res["id"]).to eq comment.id
          expect(res["content"]).to eq comment.content
          expect(res["user_id"]).to eq comment.user.id
          expect(res["article_id"]).to eq comment.article.id
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

  describe "DELETE /v1/articles/:article_id/comments/:id" do
    subject { delete(v1_article_comment_path(article, comment_id), params: params, headers: headers) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "ログインしているユーザーのコメントがある時" do
        let(:current_user) { create(:user) }
        let(:headers) { current_user.create_new_auth_token }
        let!(:comment) { create(:comment, user: current_user) }
        let(:comment_id) { comment.id }
        let(:params) { attributes_for(:comment, user: current_user.id) }

        it "コメントの削除ができる" do
          expect { subject }.to change { current_user.comments.count }.by(-1)
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

  describe "PATCH /v1/articles/:article_id/comments/:id" do
    subject { patch(v1_article_comment_path(article, comment_id), params: params, headers: headers) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "ログインしているユーザーのコメントがある時" do
        let(:current_user) { create(:user) }
        let(:headers) { current_user.create_new_auth_token }
        let(:comment) { create(:comment, user: current_user) }
        let(:comment_id) { comment.id }
        let(:params) { { comment: attributes_for(:comment, user: current_user.id) } }

        it "コメントの更新ができる" do
          expect { subject }.to change { comment.reload.content }.from(comment.content).to(params[:comment][:content])
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end
end

実装手順

まずFactoryBotを用いて
.

テストデータを作成するファイルを作ります。
.
spec/factories/comments.rb

FactoryBot.define do
  factory :comment do
    content { Faker::Lorem.paragraph }
  end
end

.

commentモデルは

.

User, Articleモデルと紐づいているので
.

FactoryBot.define do
  factory :comment do
    content { Faker::Lorem.paragraph }
   user
   article
  end
end

.

このように追記することで
.

  • build(:comment)
  • attribute_for(:comment)
    -create(:comment)

などでcommentを作成する時に
.

UserとArticleも作成されるようになります。
.

ちなみにこれは省略形で、
.

本来の形はUserなら
.

association :user, factory: :user
```です。
.

これで準備は整ったのでテストを書いていきます。

.

```xpath
 $ be rails routes |grep comment
                  v1_article_comments GET    /v1/articles/:article_id/comments(.:format)                                              v1/articles/comments#index
                                      POST   /v1/articles/:article_id/comments(.:format)                                              v1/articles/comments#create
                   v1_article_comment GET    /v1/articles/:article_id/comments/:id(.:format)                                          v1/articles/comments#show
                                      PATCH  /v1/articles/:article_id/comments/:id(.:format)                                          v1/articles/comments#update
                                      PUT    /v1/articles/:article_id/comments/:id(.:format)                                          v1/articles/comments#update
                                      DELETE /v1/articles/:article_id/comments/:id(.:format)                                          v1/articles/comments#destroy

.

テスト対象の設定

.

spec/v1/requests/articles/comments_spec.rb

RSpec.describe "V1::Articles::Comments", type: :request do

.

v1/articles/comments_controller.rb

.

のテストなのでこんな感じ。

createメソッド

テストの条件は
.

ユーザーがログインしていて、
.

コメント対象の記事が存在する時
.

コメントができる。
.

ことを確認する。

.

URLとパスの設定は
.

be rails routes

で確認!
.

.

describe "POST /v1/articles/:article_id/comments" do

subjectはAPIを叩く部分の設定で完成形は
.

subject { post(v1_article_comments_path(article),params:params,headers: headers) }

.

こちらなのですが一気に説明が難しいので
一つずつ追加していきます。
.

基本形はこちら。
.

subject { post(v1_article_comments_path) }
post(v1_article_comments_path)

で、パスを指定。

.

まず、コメントするユーザーが必要なので

.

let(:current_user) { create(:user) }

.

でユーザーを作成。
.

ログインしていないとコメントできない仕様なので
.

ログイン情報を作成する。
.

今回は
.

device_token_auth

.

を使ってログイン認証を行っています。
.

.
device_token_authについてはこちら
.

device_token_authを使った新規登録機能の実装
概要新規登録APIの実装、リクエスト、レスポンスの確認エラー解決実装内容コントローラーにv1/auth/user階層、registrations_controllerの作成registrations_controllerへのルーティング...

.
device_token_authを使ってログインするには
.

tokenを発行してheadersに送らなければならない。
.

ということで
.

let(:headers) { current_user.create_new_auth_token }

.

letで変数headers
.

{ current_user.create_new_auth_token }

で作成した
.

ログイン認証に必要なtokenを発行してheadersに代入。

.

APIを叩く際にこの情報が必要なので subjectに追加
.

subject { post(v1_article_comments_path, headers: headers) }

次に

let(:article) { create(:article) }

.

コメントする記事を作成。

let(:params) { { comment: attributes_for(:comment) } }

.

パラメーターに渡すコメントを作成。
.

コメントする記事を指定するために
.

let(:params) { { comment: attributes_for(:comment, article_id: article.id) } }

.

に修正。
.

APIを叩く際に記事とパラメーターを渡すために
.

subject { post(v1_article_comments_path(article), params: params, headers: headers) }

.

subjectに追加してAPIを叩く部分は完成です。
.

次に
APIを叩いた後にコメントが作成できているかを確認します。
.

確認する項目は以下の3つ。
.

・コメントしたユーザーのコメント数が一つ増えている。

expect { subject }.to change { current_user.comments.count }.by(1)

・リクエストの結果が正常であるか。

expect(response).to have_http_status(:ok)

・コメント内容は一致しているか。

expect(res["content"]).to eq params[:comment][:content]

be rspecで確認して通過すれば完成。

RSpec.describe "V1::Articles::Comments", type: :request do
  describe "POST /v1/articles/:article_id/comments" do
    subject { post(v1_article_comments_path(article), params: params, headers: headers) }

    context "ユーザーがログインしていて" do
      let(:current_user) { create(:user) }
      let(:headers) { current_user.create_new_auth_token }

      context "コメント対象の記事が存在する時" do
        let(:article) { create(:article) }
        let(:params) { { comment: attributes_for(:comment, article_id: article.id) } }

        it "コメントができる" do
          expect { subject }.to change { current_user.comments.count }.by(1)
          expect(response).to have_http_status(:ok)
          res = JSON.parse(response.body)
          expect(res["content"]).to eq params[:comment][:content]
        end
      end
    end
  end

indexメソッド

同じ作業は省略していきます。
.

URLとAPIで叩くパスを設定します。
.

describe "GET /v1/articles/:article_id/comments" do
    subject { get(v1_article_comments_path(article)) }
end   

.

indexのテストでは
指定した記事のコメント一覧が取得できるかを確認していきます。

let(:article) { create(:article) }

記事を作成。
.

let(:article_id) { article.id }

.

article.idを変数article_idに代入。
.

subjectに渡してあげる
.

subject { get(v1_article_comments_path(article)) }

次にコメント一覧ということで
先にコメントを作っておかなければならないので、

let!(:comment) { create_list(:comment, 3) }

.

コメントを3つ作成しておき、変数commentに代入。

.

letを付けることで先に作っておいてくれる。
.

create_listはFactoryBotのメソッドで指定した数の

.

データを作ってくれるメソッドです。
.

コメントする記事を指定するために
.

let!(:comment) { create_list(:comment, 3, article_id: article.id) }

に修正して準備は完了。
.

テスト項目は
.

・コメント数が一致しているか。(今回は3つ作っているので3つ)

expect(res.length).to eq 3

・コメントのカラムは一致しているか。

expect(res[0].keys).to eq ["id", "content", "user_id", "article_id", "created_at", "updated_at"]

・リクエストの結果が正常であるか。

expect(response).to have_http_status(:ok)

be rspecで確認して通過すれば完成。

describe "GET /v1/articles/:article_id/comments" do
    subject { get(v1_article_comments_path(article)) }

    context "任意の記事に" do
      let(:article) { create(:article) }
      let(:article_id) { article.id }

      context "コメントがある時" do
        let!(:comment) { create_list(:comment, 3, article_id: article.id) }
        it "コメントの一覧が取得できる" do
          subject
          res = JSON.parse(response.body)
          expect(res.length).to eq 3
          expect(res[0].keys).to eq ["id", "content", "user_id", "article_id", "created_at", "updated_at"]
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

showメソッド

URLとAPIで叩くパスを設定します。
.

describe "/v1/articles/:article_id/comments/:id" do
    subject { get(v1_article_comment_path(article, comment_id)) }

.

コメントの詳細ということで
任意の記事に指定したコメントがある場合を見ていきます。
.

let(:article) { create(:article) }

.

で記事作成。
.

let(:comment) { create(:comment) }
let(:comment_id) { comment.id }

.

コメント作成と変数代入
.

準備完了。

.

テスト項目は
・内容が一致しているか

expect(res["id"]).to eq comment.id
expect(res["content"]).to eq comment.content
expect(res["user_id"]).to eq comment.user.id
expect(res["article_id"]).to eq comment.article.id
expect(response).to have_http_status(:ok)

・リクエストの結果が正常であるか。

expect(response).to have_http_status(:ok)

.

be rspecで確認して通過すれば完成。
.

describe "/v1/articles/:article_id/comments/:id" do
    subject { get(v1_article_comment_path(article, comment_id)) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "指定したコメントがある場合" do
        let(:comment) { create(:comment) }
        let(:comment_id) { comment.id }

        it "コメントの詳細が見れる" do
          subject
          res = JSON.parse(response.body)
          expect(res["id"]).to eq comment.id
          expect(res["content"]).to eq comment.content
          expect(res["user_id"]).to eq comment.user.id
          expect(res["article_id"]).to eq comment.article.id
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

destroy メソッド

URLとAPIで叩くパスを設定します。
.

 describe "DELETE /v1/articles/:article_id/comments/:id" do
    subject { delete(v1_article_comment_path(article, comment_id), params: params, headers: headers) }
end
let(:article) { create(:article) }

.

で記事作成
.

コメントを削除できるのは自分のコメントのみなので
.

let(:current_user) { create(:user) }
let(:headers) { current_user.create_new_auth_token }

.

userを作成して
ログイン情報を送るためsubjectheadersを追加
.

コメントを削除するので
.

let!(:comment) { create(:comment, user: current_user) }

.
で事前にコメントを作成しておく。
.

作成者は
.

let(:current_user) { create(:user) }

.

で作ったユーザーに指定。

.

let(:params) { attributes_for(:comment, user: current_user.id) }

.

APIを叩く際に渡すパラメーターを作成。
.

準備は完了。

.

テスト項目は
・削除するとコメント数が一つ減るかどうか。

expect { subject }.to change { current_user.comments.count }.by(-1)

・リクエストの結果が正常であるか。

expect(response).to have_http_status(:ok)

.

be rspecで確認して通過すれば完成。

.

  describe "DELETE /v1/articles/:article_id/comments/:id" do
    subject { delete(v1_article_comment_path(article, comment_id), params: params, headers: headers) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "ログインしているユーザーのコメントがある時" do
        let(:current_user) { create(:user) }
        let(:headers) { current_user.create_new_auth_token }
        let!(:comment) { create(:comment, user: current_user) }
        let(:comment_id) { comment.id }
        let(:params) { attributes_for(:comment, user: current_user.id) }

        it "コメントの削除ができる" do
          expect { subject }.to change { current_user.comments.count }.by(-1)
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

updateメソッド

URLとAPIで叩くパスを設定します。
.

describe "PATCH /v1/articles/:article_id/comments/:id" do
    subject { patch(v1_article_comment_path(article, comment_id), params: params, headers: headers) }

.

更新ができるのは自分のコメントのみなので
.

let(:current_user) { create(:user) }
let(:headers) { current_user.create_new_auth_token }

.

userを作成して
ログイン情報を送るためsubjectheadersを追加
.

コメントを更新するので
.

let!(:comment) { create(:comment, user: current_user) }

.
で事前にコメントを作成しておく。
.

作成者は
.

let(:current_user) { create(:user) }

.

で作ったユーザーに指定。

 let(:params) { attributes_for(:comment, user: current_user.id) }

.

APIを叩く際に渡すパラメーターを作成。
.

準備は完了。
.

テスト項目は
・コメントが更新されているのか確認

expect { subject }.to change { comment.reload.content }.from(comment.content).to(params[:comment][:content])

・リクエストの結果が正常であるか。

expect(response).to have_http_status(:ok)

.

`be rspec`で確認して通過すれば完成。

.

describe "PATCH /v1/articles/:article_id/comments/:id" do
    subject { patch(v1_article_comment_path(article, comment_id), params: params, headers: headers) }

    context "任意の記事に" do
      let(:article) { create(:article) }

      context "ログインしているユーザーのコメントがある時" do
        let(:current_user) { create(:user) }
        let(:headers) { current_user.create_new_auth_token }
        let(:comment) { create(:comment, user: current_user) }
        let(:comment_id) { comment.id }
        let(:params) { { comment: attributes_for(:comment, user: current_user.id) } }

        it "コメントの更新ができる" do
          expect { subject }.to change { comment.reload.content }.from(comment.content).to(params[:comment][:content])
          expect(response).to have_http_status(:ok)
        end
      end
    end
  end

.

全部を合わせて完成です!

関連記事

Railsでログイン中のユーザーが記事にコメント出来るAPIを実装 
概要ログインしているユーザーが記事にコメントできるAPIを実装.テストはこちら..【使用したgem】devise_token_authログイン情報をtokenで認証active_model_selializerJSONオブ...
RSpecでコメントモデルのテストを実装 Rails
概要コメントモデルのテストを実装【 使用gem】gem "factory_bot_rails"テストデータの作成を手伝ってくれるGemです。gem "faker"ダミーデータを作成するgem...

コメント

タイトルとURLをコピーしました