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

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

新規登録して質問してみよう
ただいま回答率
87.20%
Ruby on Rails 6

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

RSpec

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

解決済

Rspecで音声ファイルの設定が出来ず、hashを渡すことができない。また、user can't be blankが解消できない

senseIY
senseIY

総合スコア205

Ruby on Rails 6

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

RSpec

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

1回答

0評価

0クリップ

420閲覧

投稿2022/03/21 06:57

編集2022/03/23 14:42

解決したいこと

現在ポートフォリオ作成中のプログラミング入門者です。テストを書くのにRspecを使ってみようと考えたので、Rspecを使い、テストを作成しています。ですが、音声ファイルの検証テストを書く際にエラーが起こってしまいました。流れを書くために、最初のエラーも書いています。

最初に発生していたエラー

Failures: 1) DictumUser test for DictumUser when user input invalid parameter when user is deleted gogaku is deleted too Failure/Error: gogaku.file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'Night_Sea.mp3'), 'audio/mpeg', :binary) NoMethodError: ... 6.2.1/lib/factory_bot/strategy_syntax_method_registrar.rb:28:in `block in define_singular_strategy_method' # ./spec/models/dictum_user_spec.rb:115:in `block (5 levels) in <top (required)>' Finished in 0.12316 seconds (files took 1.32 seconds to load) 10 examples, 1 failure Failed examples: rspec ./spec/models/dictum_user_spec.rb:117 # DictumUser test for DictumUser when user input invalid parameter when user is deleted gogaku is deleted too

該当するソースコード

#/spec/factories/dictum_users.rb FactoryBot.define do factory :kobe, class: DictumUser do name {"kobe"} email {"kobe@example.com"} password {"foobar"} password_confirmation {"foobar"} end #/spec/factories/gogakus.rb FactoryBot.define do factory :gogaku do subject {"English"} body {"in trip"} after(:build) do |gogaku| gogaku.file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'Night_Sea.mp3'), 'audio/mp3', :binary) end answer {"none"} end end # spec/models/dictum_user_spec.rb RSpec.describe DictumUser, type: :model do # pending "add some examples to (or delete) #{__FILE__}" describe "test for DictumUser" do context "should be valid" do user = FactoryBot.build(:kobe) it "create instance accurately" do expect(user.name).to eq "kobe" expect(user.email).to eq "kobe@example.com" expect(user.password).to eq user.password_confirmation expect(user).to be_valid end end context "when user input invalid parameter" do context "when name which user input is empty" do user = FactoryBot.build(:kobe, name: "") it " regard the user as invalid" do expect(user).not_to be_valid end end context "when name which user input is too long" do user = FactoryBot.build(:kobe, name: "a"*51) it " regard the user as invalid" do expect(user).not_to be_valid end end context "when email which user input is empty" do user = FactoryBot.build(:kobe, email: "") it "regard the user as invalid" do expect(user).not_to be_valid end end context "when email which user input is invalid format" do user = FactoryBot.build(:kobe, email: "email.com") it "regard the user as invalid" do expect(user).not_to be_valid end end context "when email which user input is too long" do user = FactoryBot.build(:kobe, email: "a"*244+"@example.com") it "regard the user as invalid" do expect(user).not_to be_valid end end context "when password which user input is empty " do user = FactoryBot.build(:kobe, password: " "*6, password_confirmation: " "*6) it "regard the user as invalid" do expect(user).not_to be_valid end end context "when password which user input is too short" do user = FactoryBot.build(:kobe, password: "hoge", password_confirmation: "hoge") it "regard the user as invalid" do expect(user).not_to be_valid end end context "when email which user input isn`t unique" do user = FactoryBot.build(:kobe) it "regard the user as invalid" do user.save user2 = user.dup user2.email = user2.email.upcase user2.save expect(user2).not_to be_valid end end #エラーが起きているのはここから context "when user is deleted" do user = FactoryBot.build(:kobe) gogaku = FactoryBot.build(:gogaku) it "gogaku is deleted too" do user.save gogaku.file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'Night_Sea.mp3'), 'audio/mpeg') pending gogaku.save user.gogakus.create(gogaku) expect(Gogaku.count).to eq 1 user.destroy expect(Gogaku.count).to eq 0 end end end #/spec/models/gogaku_spec.rb require 'rails_helper' RSpec.describe Gogaku, type: :model do describe "test for gogaku" do dictum_user = FactoryBot.build(:kobe) gogaku = dictum_user.gogakus.build({subject: "a",body: "a",file: Rack::Test::UploadedFile.new('spec/fixtures/files/Night_Sea.mp3', 'audio/mp3'),answer: "a"}) it "gogaku should be valid" do expect(gogaku).to be_valid end end end #### ここまで  #gogaku.rb class Gogaku < ApplicationRecord belongs_to :dictum_user default_scope -> { order(created_at: :desc) } validates :subject,presence:true validates :body, presence:true has_one_attached :file validates :dictum_user_id, presence: true validates :file,presence:true validates :file,size: { less_than: 5.megabytes, message: "should be less than 5MB" } end

自分で試したこと

https://gist.github.com/h-sakano/50092b1c17fe8ddc0bbe5382fb8587a4
https://qiita.com/h-sakano/items/fc297f91a7bafc0b4d6d
・最初にこの方たちの記事を参考にさせていただきました。ですが、私の場合、

# spec/factories/dictum_users.rb after(:build) do |gogaku| gogaku.file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'Night_Sea.mp3'), 'audio/mpeg', :binary) end

このように記述してもエラーが直りませんでした。
・次に
https://qiita.com/tatematsu-k/items/1cdd946cd38e69d16340
この方の記事を参考にさせていただきました。rails6.1.5を使っていたので以下を追及

#rails_helper.rb FactoryBot::SyntaxRunner.class_eval do include ActionDispatch::TestProcess include ActiveSupport::Testing::FileFixtures end

これを追記したところエラーに変化が

An error occurred while loading ./spec/models/dictum_user_spec.rb. Failure/Error: user.gogakus.build(FactoryBot.build(:music)) ArgumentError: When assigning attributes, you must pass a hash as an argument, Gogaku passed. # ./spec/models/dictum_user_spec.rb:117:in `block (4 levels) in <top (required)>' # ./spec/models/dictum_user_spec.rb:114:in `block (3 levels) in <top (required)>' # ./spec/models/dictum_user_spec.rb:27:in `block (2 levels) in <top (required)>' # ./spec/models/dictum_user_spec.rb:5:in `block in <top (required)>' # ./spec/models/dictum_user_spec.rb:3:in `<top (required)>' Finished in 0.00007 seconds (files took 0.88052 seconds to load) 0 examples, 0 failures, 1 error occurred outside of examples

どうやらエラーによると、引数はハッシュで渡さないといけないというエラーのようです。しかし、私の場合、user.gogakus.build(FactoryBot.build(:music))のようにしているので:musicのシンボルがキーでその中身がバリューのハッシュの構造になっていると考えたのですが、間違っているでしょうか?
また、なぜか「when user is deleted gogaku is deleted too」の部分でsaveしているにもかかわらず下記のエラーが出ます

Pending: (Failures listed here are expected and do not affect your suite's status) 1) DictumUser test for DictumUser when user input invalid parameter when user is deleted gogaku is deleted too # No reason given Failure/Error: user.gogakus.create(gogaku) ActiveRecord::RecordNotSaved: You cannot call create unless the parent is saved # ./spec/models/dictum_user_spec.rb:125:in `block (5 levels) in <top (required)>'

仕方なくfactrybotを使わないで直接書き込むことにしました。
以下のように記述しました

require 'rails_helper' RSpec.describe Gogaku, type: :model do describe "test for gogaku" do dictum_user = FactoryBot.build(:kobe) gogaku = dictum_user.gogakus.build({subject: "a",body: "a",file: Rack::Test::UploadedFile.new('spec/fixtures/files/Night_Sea.mp3', 'audio/mp3'),answer: "a"}) it "gogaku should be valid" do expect(gogaku).to be_valid end end end

このように記述したところ、エラーが変わりました。

Failures: 1) DictumUser test for DictumUser should be valid create instance accurately Failure/Error: expect(user).to be_valid expected #<DictumUser id: nil, name: "kobe", email: "kobe@example.com", created_at: nil, updated_at: nil, password_digest: [FILTERED], admin: false> to be valid, but got errors: Email has already been taken # ./spec/models/dictum_user_spec.rb:24:in `block (4 levels) in <top (required)>' 2) Gogaku test for gogaku gogaku should be valid Failure/Error: expect(gogaku).to be_valid expected #<Gogaku id: nil, subject: "a", body: "a", file: nil, answer: "a", dictum_user_id: nil, created_at: nil, updated_at: nil> to be valid, but got errors: Dictum user can't be blank # ./spec/models/gogaku_spec.rb:16:in `block (3 levels) in <main>' Finished in 0.2429 seconds (files took 1.65 seconds to load) 11 examples, 2 failures, 1 pending Failed examples: rspec ./spec/models/dictum_user_spec.rb:19 # DictumUser test for DictumUser should be valid create instance accurately rspec ./spec/models/gogaku_spec.rb:12 # Gogaku test for gogaku gogaku should be valid

Dictum user can't be blankとエラーが返ってきたので一応ハッシュで値をわたせているようです。ですが、今度はDictum Userが空ではいけないというエラーが出てしまいました。これはモデルでhas_manyの関係になっていることが原因かと考えられます(DictumUserが親Gogakuが子)。しかも、ここで前はパスしていたテスト(DictumUserが正しく作れるか確認するテスト)が失敗してしまいました。理由は恐らく以下のことも試したことが原因だと考えられます。
・FactoryBot.createを使ったから
・dictum_user = DictumUser.new(name: "abc",email: "abc@example.com", password: "foobar", password_confirmation: "foobar")のように直接書き込んだから?作成したuserのemailが違うので可能性は極めて低いが念のため記述
これらの操作しかしていないのになぜemailのバリデーションに引っかかってしまったのか分かりません。テスト終了後に自動的にロールバックされるとの情報があったのでそう思い込んでいましたが、どうなのでしょうか?
ここで詰まってしまいました。

その他

・ruby3.0.3 rails6.1.5 環境構築はDockerで行いました。wsl2のUbuntuを使っています。

プログラミング入門者なので何かしら間違えた認識をしているかもしれません。何かしらアドバイスがあればよろしくお願いいたします。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Ruby on Rails 6

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

RSpec

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