質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

2474閲覧

request spec で 不正なパラメータのテストだけ ActionController::UnknownFormat: になってしまう。

mikannOishiii

総合スコア6

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2020/05/02 14:29

前提・実現したいこと

request spec において、
contextでパラメータが妥当な場合と不正な場合で場合分けして、
create のテストを通したいです。

発生している問題・エラーメッセージ

パラメータが妥当なテストは通るのに、不正な場合のテストだけActionController::UnknownFormat:になってしまいます。

両者のテストの記述の違いは、
record: attributes_for(:record)
record: attributes_for(:record, :invalid) の違いだけです。
(※結果(expect)はもちろん成功の場合とエラーの場合でそれぞれ違います)

該当のソースコード

日付に対して数値を登録していくフォームがあり、数値しか登録できないように validation をかけています。Factory.bot にて、trait を使って invalid なデータを定義しています。

ruby

1# app/models/record.rb 2 3class Record < ApplicationRecord 4 belongs_to :user 5 6 validates :user_id, presence: true 7 validates :date, presence: true, uniqueness: true 8 validates :memo, length: { maximum: 20 } 9 10 with_options numericality: { only_integer: true }, allow_nil: true do 11 validates :m_sbp 12 validates :m_dbp 13 end 14end

ruby

1FactoryBot.define do 2 factory :record do 3 date { Time.now } 4 m_sbp { 147 } 5 m_dbp { 93 } 6 memo { "MyMemo" } 7 association :user 8 9 trait :invalid do 10 m_sbp { "str" } 11 end 12 end 13end
request_spec

こちらの qiita の記事「Rails5でコントローラのテストをController specからRequest specに移行する」を参考にして作成しました。ただし本アプリの rails のバージョンは rails6 で作っています。

ruby

1# spec/requests/records_request_spec.rb 2 3require 'rails_helper' 4 5RSpec.describe "Records", type: :request do 6 7 describe 'POST #create' do 8 let(:user) { create(:user) } 9 10 context "パラメータが妥当な場合" do 11 before do 12 sign_in user 13 end 14 15 it "リクエストが成功すること" do 16 post records_url, params: { record: attributes_for(:record) } 17 expect(response.status).to eq 302 18 end 19 20 it "recordが登録されること" do 21 expect do 22 post records_url, params: { record: attributes_for(:record) } 23 end.to change(Record, :count).by(1) 24 end 25 26 it "リダイレクトすること" do 27 post records_url, params: { record: attributes_for(:record) } 28 expect(response).to redirect_to root_url 29 end 30 end 31 32 context "パラメータが不正な場合" do 33 before do 34 sign_in user 35 end 36 37 it "リクエストに成功すること" do 38 post records_url, params: { record: attributes_for(:record, :invalid) } 39 expect(response.status).to eq 200 40 end 41 42 it "recordが登録されないこと" do 43 expect do 44 post records_url, params: { record: attributes_for(:record, :invalid) } 45 end.to_not change(Record, :count) 46 end 47 48 it "エラーが表示されること" do 49 post records_url, params: { record: attributes_for(:record, :invalid) } 50 expect(response.body).to include "朝の最高血圧は数値で入力してください" 51 end 52 end 53 end
コントローラ

新規作成も更新も同じモーダルフォーム(form_for)で行っているため、日付に紐づくデータがなければ create、あれば update するようにしています。(def update も全く同じ記述なのでこちらは別途なんとかしたい。)

ruby

1# app/controllers/records_controller.rb 2 3class RecordsController < ApplicationController 4 5 def create 6 @record = current_user.records.find_by(date: params[:record][:date]) 7 respond_to do |format| 8 if @record.nil? 9 @record = Record.new(record_params) 10 if @record.save 11 format.html{ redirect_to root_url, notice: "記録を作成しました。"} 12 else 13 format.js { render :new } 14 end 15 else 16 if @record.update(record_params) 17 format.html { redirect_to root_url, notice: "記録を更新しました。" } 18 else 19 format.js { render :new } 20 end 21 end 22 end 23 end

エラーメッセージ

Records POST #create パラメータが妥当な場合 リクエストが成功すること #=>成功 recordが登録されること #=>成功 リダイレクトすること #=>成功 パラメータが不正な場合 リクエストに成功すること (FAILED - 1) recordが登録されないこと (FAILED - 2) エラーが表示されること (FAILED - 3) Failures: 1) Records POST #create パラメータが不正な場合 リクエストに成功すること Failure/Error: respond_to do |format| if @record.nil? @record = Record.new(record_params) if @record.save format.html{ redirect_to root_url, notice: "記録を作成しました。"} else format.js { render :new } end else if @record.update(record_params) ActionController::UnknownFormat: ActionController::UnknownFormat

※ エラー3つとも同じエラー内容なので省略

試したこと

attributes_for(:record) だと通って、attributes_for(:record, :invalid) だと通らないので、traitがよくないのかなと思い、attributes_forのところに直接データを突っ込んで見つなどしましたが、同じエラーでできませんでした。

また、factory_bot で trait を使わず新たに不正なデータのレコードを登録してやってみましたが、こちらはNameError: uninitialized constant InvalidRecord でできませんでした。

補足情報(FW/ツールのバージョンなど)

・ruby 2.6.5
・rails 6.0.2
・rspec-rails 4.0.0.beta4

何かヒントや参考記事だけでも良いのでアドバイスいただけると大変助かります。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

こちらの記事を参考に自己解決できました。
パラメータが妥当の場合は、format.html{ redirect_to root_url } を返しますが、
パラメータが不正の場合は、format.js { render :new } を返すため、
jsに対応したspecの記述に format: :js が必要でした。

context "パラメータが不正な場合" do before do sign_in user end it "リクエストに成功すること" do post records_url, params: { record: attributes_for(:record, :invalid), format: :js } expect(response.status).to eq 200 end it "recordが登録されないこと" do expect do post records_url, params: { record: attributes_for(:record, :invalid), format: :js } end.to_not change(Record, :count) end it "エラーが表示されること" do post records_url, params: { record: attributes_for(:record, :invalid), format: :js } expect(response.body).to include "朝の最高血圧は数値で入力してください" end end

投稿2020/05/04 05:39

mikannOishiii

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問