【rails】request spec(get・post)

※本サイトで紹介している商品・サービス等の外部リンクには、アフィリエイト広告が含まれる場合があります。

controllerのテスト

controllerにリクエストを送って、想定したレスポンス(httpのステータス)が返ってくるかを確認する(request spec

controllerの役割を果たせているか確認する

今回は、getリクエストとpostリクエストについてそれぞれテストをしてみる

getリクエスト
  1. 確認したいことを決める
    今回は「リクエストを送って、200や正しいレスポンスが返ってくるか」確認したい
  2. リクエストを送る(ダミーデータみたいなもの)
  3. 200ステータスを確認&レスポンスを確認

postリクエスト
  1. 確認したいことを決める
    今回は「リクエストを送って、記事が保存されるか」確認したい
  2. リクエストを送る(ダミーデータみたいなもの)
  3. postしたパラメーターと、保存された内容が一致しているか確認する

今回はarticles controllerのテストを行う


実際に書いてみる(getリクエスト)

1.なにを確認したいのか決める

indexにレスポンスを送り、正しいレスポンスが返ってくるか確認したい

  def index
    @articles = Article.all
  end

2.リクエストを送るデータを作る

今回はターミナルからファイルを作ってみる↓

rails g rspec:request article

#=> create spec/requests/articles_spec.rb

すると、spec/requests/articles_spec.rbのファイルが出来上がる↓

require 'rails_helper'

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

↑を↓に書き換える

'GET /articles'に対して、‘200ステータスが返ってくる’かどうか確認したい

require 'rails_helper'

RSpec.describe 'Articles', type: :request do
  describe 'GET /articles' do
    it '200ステータスが返ってくる' do
      get articles_path
      expect(response).to have_http_status(200)
    end
  end
end

it以降は‘確認したい内容’を入れる

ダブルクォーテーションはシングルクォーテーションに変えておく(ほかと統一させる)

get articles_path
getというメソットのおかげで、articles_pathにリクエストを送ることができる

expect(response).to have_http_status(200)
→httpステータスが「200」のresponseが返ってくればokという意味になる

これらはrspecの特殊な書き方だったりする


今の状態でリクエストを送っても通ることは通る

ただ、本当に検証したいのは「記事がある状態でリクエストが通るかどうか」

記事のない状態で検証しても意味がない・・・

記事を用意した状態で、レスポンスが返ってくるのか検証する


データ内に、検証用のダミーデータ(記事)を用意する

RSpec.describe 'Articles', type: :request do
  let!(:user) { create(:user) }
  let!(:articles) { create_list(:article, 3, user: user) }

let!(:user) { create(:user) }
→記事を作るために、まずはuserを作成する

記事を複数作るのでarticlesとし、creat_listを使う
:articleを作ること、3記事作ること、先ほど作った:userと紐づけること)を記載する


3.ターミナルでテストを実行する

bundle exec rspec spec/requests/articles_spec.rb

成功!

この「」が緑→テストが通った赤→テストは失敗という意味


実際に書いてみる(postリクエスト)

1.なにを確認したいのか決める

「記事が保存されているか」を確認したい

  def create
    @article = current_user.articles.build(article_params)
    if @article.save
      redirect_to article_path(@article),
                  notice: '保存できました'
    else
      flash.now[:error] = '保存に失敗しました'
      render :new
    end
  end

articles_controller.rbcreateの部分はこちら↑

記事を作成後、redirect_toしている

redirect_toのときは「200」じゃなくて、「302」が返ってくる

ただ、「redirect_to=記事が保存できている」わけではない

(保存されてなくてもredirect_toされることがある)

なので、「200」「302」が返ってくるかではなく、記事が保存されているかを確認できるようにする


2.リクエストを送るためのデータを作る

  describe 'POST /articles' do
    it '記事が保存される' do
      article_params = attributes_for(:article)
      post articles_path({article: article_params})
      expect(response).to have_http_status(302)
    end
  end

postするときはパラメーターを指定しないといけない

article_paramsとしたとき、attributes_for(:article)を使うと↓の内容でいい感じにパラメーターを作ってくれる

attributes_forは、factory_botで用意されている便利なメソッドのひとつ

これでリクエストを送ると、問題なくステータス「302」が返ってくるようになる

次は、「記事が保存されているか」を確認する方法を考える


記事が保存されているか、どう確認する?

  describe 'POST /articles' do
    it '記事が保存される' do
      article_params = attributes_for(:article)
      post articles_path({article: article_params})
      expect(response).to have_http_status(302)
      expect(Article.last.title).to eq(article_params[:title])
      expect(Article.last.content).to eq(article_params[:content])
    end
  end

パラメーターで送ったarticle_paramsの中身=最後に保存された記事の中身

以下が一致していれば、記事は保存できていることがわかる!

  • Article.last.title = article_params[:title]
  • Article.last.content = article_params[:content]

このままのコードだとcontentだけエラーが起きる

Article.last.contentでは、contentの本文だけじゃなく、インスタンスとして返ってきてしまう


「文字列」を取得するにはどうしたらいいのか?

Article.last.content.body.to_plain_text

コンソール画面で上記のとおり入力してみる

文字列だけ取れた!

ひとまず完成したコードはこちら↓

  describe 'POST /articles' do
    it '記事が保存される' do
      article_params = attributes_for(:article)
      post articles_path({article: article_params})
      expect(response).to have_http_status(302)
      expect(Article.last.title).to eq(article_params[:title])
      expect(Article.last.content.to_plain_text).to eq(article_params[:content])
    end
  end

この状態でテストを実行しても失敗する

現状、ログインしていないからcreateが出来ず、失敗する


ログインの処理を書いていく

deviceにはsign_inというメソッドが用意されている

あとはuserと指定してしまえばログイン状態を作ることができる(簡単!)

  describe 'POST /articles' do
    context 'ログインしている場合' do
      before do
        sign_in user
      end

      it '記事が保存される' do
        article_params = attributes_for(:article)
        post articles_path({article: article_params})
        expect(response).to have_http_status(302)
        expect(Article.last.title).to eq(article_params[:title])
        expect(Article.last.content.to_plain_text).to eq(article_params[:content])
      end
    end
  end

rspecでdeviceの機能を使うためには、rspecに設定をする必要がある(今のままでは使えない)


spec/rails_helper.rbにFactoryBotの設定を書いたように、Deviseincludeについても記載する

  config.include FactoryBot::Syntax::Methods
  config.include Devise::Test::IntegrationHelpers, type: :request

request specDeviceをインストールします」という意味になる

これで、ログインした状態でリクエストを送ることができる


3.ターミナルでテストを実行する

bundle exec rspec spec/requests/articles_spec.rb

成功!!

#DAY14