DK’s diary

プログラミング初学者による発信

Rspecによるテスト:外部キーが設定されている際のモデルテスト

扱うモデルについて

メッセージ投稿に関するMessageモデルを例に説明していきます!
私の作成しているアプリのmessagesテーブルは以下のようになっており、
user_idとroom_idの2つを外部キーとして設定しています。
また、空での投稿を防ぐためにcontentにバリデーションをかけています。

Column Type Options
------- ------- -----------------
user_id integer foreign_key: true
room_id integer foreign_key: true
content string null: false
image string
外部キーを考慮せずにテストを行うと・・・

今回は"contentとimageがあれば投稿できる"という項目でテストを行います。
factory_botを使ってテンプレートを作成しました。
factory_botの説明についてはこちら↓↓
https://dkdkdk3.hatenablog.com/entry/2020/06/07/005240

spec > factories > messages.rb

FactoryBot.define do
  factory :message do
    content  {"テストです。"}
    image    {"test.jpg"}
  end
end


テストについては以下のように記述しました。
spec > models > message_spec.rb

require 'rails_helper'
describe Message do
  describe '#create' do
    it "contentとimageがあれば投稿できる" do
      message = build(:message)
      expect(message).to be_valid
    end
  end
end


この内容でテストを実行すると、

 1) Message#create contentとimageがあれば投稿できる
     Failure/Error: expect(message).to be_valid
       expected #<Message id: nil, content: "テストです。", image: "test.jpg", user_id: nil, created_at: nil, updated_at: nil, room_id: nil> to be valid, but got errors: Userを入力してください, Roomを入力してください

とテストは通りません。
最下部に、"got errors: Userを入力してください, Roomを入力してください"とあります。
MessageモデルにはUserとRoomモデルを外部キーに設定しており、
これらが無いためにエラーを起こしています。


テストにおける外部キーの設定方法

Messageモデルのテスト用にUserとRoomの情報をfactory_botで作成しました。
Roomに関しては個人間でチャットをするための部屋を用意しただけなので、カラムは作成していません。
spec > factories > users.rb

FactoryBot.define do
  factory :user do
    username              {"test"}
    email                 {"test@gmail.com"}
    password              {"000000"}
    password_confirmation {"000000"}
  end
end

spec > factories > rooms.rb

FactoryBot.define do
  factory :room do
  end
end


外部キーを使用するための準備はできました!
テストを書いていきましょう!
spec > models > message_spec.rb

require 'rails_helper'
describe Message do
  describe '#create' do
    it "contentとimageがあれば投稿できる" do
      user = create(:user)
      room = create(:room)
      message = build(:message, user_id: user.id, room_id: room.id)
      expect(message).to be_valid
    end
  end
end

UserとRoomの情報をcreateメソッドであらかじめ登録します。
一時的にテスト用のDBに保存しておく必要があるためです。
*buildメソッドだとDBに登録されないのでテストは通りません。

そのあとにMessageの情報を呼び出して外部キーの設定も記述します。
*この記述でテストが終わるのでbuildメソッドで大丈夫です!

Message
  #create
    contentとimageがあれば投稿できる

Finished in 1.12 seconds (files took 1.59 seconds to load)
1 example, 0 failures

これでテストが通るようになりました!


ちなみに試行錯誤している途中で、
Messageのfactory_botに外部キーの情報を記述してもテストは通りました。
spec > factories > messages.rb

FactoryBot.define do
  factory :message do
    content  {"テストです。"}
    image    {"test.jpg"}
    user     {build(:user)}
    room     {build(:room)}
  end
end

テストの記述はこれです。
spec > models > message_spec.rb

require 'rails_helper'
describe Message do
  describe '#create' do
    it "contentとimageがあれば投稿できる" do
      message = build(:message)
      expect(message).to be_valid
    end
  end
end

こっちでもテストは通るのですが、
テストを記述するファイル(spec > models > message_spec.rb)に外部キーの情報を書いておらず、
全体像が把握できないのであまり良い書き方では無いのかなと思います。