0
0

More than 1 year has passed since last update.

[初心者log]Rails, RSpecにてPostの単体テスト

Posted at

本記事の目的

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を連発するのはあまりよろしくないと学びました。

参考になった記事

【Rails6】 RSpecによるReviewのモデル単体テストの実装

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0