#本記事の目的
RSpec,Factry_botを用いてUserモデルと関連付いたPostモデルの単体テストを書いたので記事としてまとめておきます。
##Postのカラム
xxx_create_posts.rb
class CreatePosts < ActiveRecord::Migration[6.1]
def change
create_table :posts do |t|
t.integer :post_field
t.string :content
t.references :user, foreign_key: true
t.timestamps
end
add_index :posts, [:user_id, :created_at]
end
end
##Postのモデル
app/model/post.rb
class Post < ApplicationRecord
belongs_to :user
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
validates :post_field, presence: true
end
##gem紹介
・
・
・
group :development, :test do
gem "rspec-rails"
gem "factory_bot_rails"
end
##rails_helperの設定
api/spec/rails_helper.rb
RSpec.configure do |config|
#Factory_botのメソッドを使用する際に、クラス名の指定を省略
config.include FactoryBot::Syntax::Methods #←追加
この記述により、
user = FactoryBot.create(:user)
といった記述をしたいとき、
user = create(:user)
といったように省略できるようになります。
##FactoryBot内の記述
spec/factories/users.rb
FactoryBot.define do
factory :user do
name { "test" }
sequence(:email) { |n| "test#{n}@example.com" }
password { "password" }
profile { "僕はhogehogeです。よろしくお願いいたします。" }
end
end
spec/factories/posts.rb
FactoryBot.define do
factory :post do
content { "test!" }
post_field { Random.rand(1..10) }
association :user
end
end
###失敗例
spec/models/post_spec.rb
require 'rails_helper'
RSpec.describe Post, type: :model do
const "バリデーションについて" do
it "user_id, content, post_fieldがあれば有効であること" do
expect(create(:post)).to be_valid
end
it "user_idがなければ無効であること" do
post = create(:post, user_id: nil)
post.valid?
expect(post.errors[user_id]).to include("can't be blank")
end
・
・
・
end
end
このように記述してしまうと、
"user_id, content, post_fieldがあれば有効であること"で作成したpostと重複が発生してしまい、エラーになってしまいました。
###成功例
spec/model/post_spec.rb
require 'rails_helper'
RSpec.describe Post, type: :model do
before do
@post = build(:post)
end
describe "正常値と異常値の確認について" do
context "バリデーションについて" do
it "user_id,content,post_fieldがあれば有効であること" do
expect(create(:user)).to be_valid
expect(@post.errors).to be_empty
end
it "contentがなければ無効であること" do
@post.content = ""
@post.valid?
expect(@post.errors[:content]).to include("can't be blank")
end
it "user_idがなければ無効であること" do
@post.user_id = nil
@post.valid?
expect(@post.errors[:user_id]).to include("can't be blank")
end
it "post_fieldがなければ無効であること" do
@post.post_field = nil
@post.valid?
expect(@post.errors[:post_field]).to include("can't be blank")
end
end
context "他のモデルとのアソシエーションについて" do
let(:association) do
described_class.reflect_on_association(target)
end
context "Userモデルとのアソシエーション" do
let(:target) { :user }
it "Userとの関連付けはbelongs_toであること" do
expect(association.macro).to eq :belongs_to
end
end
end
end
end
事前にbeforeでpostをbuild(DBに保存されない)しておいて、のちにuserをcreate(DBに保存される)すればうまくいきました。
specの中でcreateを連発するのはあまりよろしくないと学びました。
##参考になった記事