[Rails] FactoryBot使ってモデルスペックを作成する

学習記録

はじめに

モデルスペックの作成をしていきましょう。

FactoryBotを使用しテストデータを作成する点も意識します。

FactoryBotとは?

FactoryBotとは、テストデータを作成するためのgemです。Railsでは開発環境、テスト環境、本番環境と使うデータベースを切り離しており、テスト環境ではテストの前提となるデータをテスト実行前に投入し、次のテストを実施するまでにはもとに戻すといったことをしています。

FactoryBotの使い方

  • FactoryBotを使うためのファクトリファイルを用意する。
  • ファクトリファイルを使ってテスト用のデータベースにテストデータを投入する。

FactoryBotでデータを作成するためのテンプレートをファクトリファイルと呼んだりします。

作業の流れ

  • Rspecをドキュメント形式に変更
  • FactoryBotの設定
  • ファクトリファイルの作成
  • モデルスペックの作成

Rspecをドキュメント形式に変更

describe()context()it()の各メソッドに渡されるドキュメント文字列を確認するには、ドキュメントフォーマッタを使用します。 メソッドに渡されたドキュメント文字列を見るにも、ドキュメントフォーマッタを使用するので、下記の設定をしましょう。

--format documentation

FactoryBotの設定

FactoryBotの省略設定

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

通常、FactoryBotのデータを呼び出す際は、FactoryBot.create(:user) のような書き方をします。

上記の設定をすることで、先頭に記述しているFactoryBot. を省略して create(:user) だけで記述できるようになります。

ファクトリファイルの作成

FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "user_#{n}@example.com" }
    password { 'password' }
    password_confirmation { 'password' }
  end
end

sequence ユニークな値は、シーケンスを使って生成できます。

FactoryBot.define do
  factory :post do

    sequence(:title, "title_1")
    content { 'Content' }
    status { 'todo' }
    deadline { 1.week.from_now }
    association :user
  end
end

コードを紐解く

sequence(:title, "title_1")

こちらのsequenceの書き方はString#nextを使った書き方です。変えたい場所が末尾の場合のみ使えます。なのでemailでは使えなかったのですね。

irb(main):022:0> 'title_1'.next
=> "title_2"
irb(main):023:0> 'title_2'.next
=> "title_3"
irb(main):024:0> 'title_3'.next
=> "title_4"
irb(main):025:0> 'user_#{n}@example.com'.next
=> "user_\#{n}@example.con"

下記の書き方と本質的には同じですが、上記のほうがスッキリしていて好ましいでしょう。

sequence(:title) { |n| "title_#{n}" }

モデルスペックの作成

Postモデルのvalidationに関するテストを記述しましょう。

  • すべての属性で有効
  • titleなしでは無効
  • statusがないと無効
  • 重複したタイトルでは無効
  • 別のタイトルで有効
require 'rails_helper'

RSpec.describe Post, type: :model do
  describe 'validation' do
    it 'is valid with all attributes' do
      post = build(:post)
      expect(post).to be_valid
      expect(post.errors).to be_empty
    end

    it 'is invalid without title' do
      post_without_title = build(:post, title: "")
      expect(task_without_title).to be_invalid
      expect(task_without_title.errors[:title]).to eq ["can't be blank"]
    end
    
    it 'is invalid without status' do
      post_without_status = build(:post, status: nil)
      expect(post_without_status).to be_invalid
      expect(post_without_status.errors[:status]).to eq ["can't be blank"]
    end
    
    it 'is invalid with a duplicate title' do
      post = create(:post)
      post_with_duplicated_title = build(:post, title: post.title)
      expect(post_with_duplicated_title).to be_invalid
      expect(post_with_duplicated_title.errors[:title]).to eq ["has already been taken"]
    end
    
    it 'is valid with another title' do
      post = create(:task)
      post_with_another_title = build(:post, title: 'another_title')
      expect(post_with_another_title).to be_valid
      expect(post_with_another_title.errors).to be_empty
    end
  end
end

describe (RSpec.describe)はテストのグループ化を宣言します。

it do ... end の中の記述がパスすればそのテストが通るということになります。

expect(X).to eq Y 「XがYに等しいことを期待する」という意味になります。

マッチャについて

expectの文で使っている toeqbe_〇〇 のような記述をマッチャと言います。マッチャとは英語でmatcherのことなので、「XとYを比較して、自分のルールに合致しているか判断する述語のこと」です。

Xが期待値、Yが実際の値といういことです。

expect(X) to 〇〇 Y

to

「~であること」を期待します。

eq

期待値と実際の値が「等しい」かどうか検証しています。

be_valid / be_invalid

valid?メソッドや、invalid?メソッドをbe_valid のような形で検証できます。

expect(user).to be_valid    # user.valid? が trueになればパスする

be_empty

こちらもempty?メソッドを間接的に通しているようなイメージです。

expect(user).to be_empty   # user.empty? が trueになればパスする

buildメソッドを使っている理由

build は結論から言ってnew と同じだと考えて貰って大丈夫でしょう。(古いRailsでは外部キーがつくかどうかの違いがあったみたいです。)

しかしFactoryBotでインスタンスを作成するメソッドはbuildcreateしか用意されていません。

データベースに保存する必要が無いときはbuild 、データベースにデータを保存しインスタンスを永続化させたいときはcreateを使うようにしましょう。

終わりに

Rspecは書き方がいろいろあるので難しく感じるかもしれませんが、少しずつ慣れていきましょう!

参考記事

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
はじめにRSpecは難しい、よくわからない、といったコメントをときどき見かけます。確かにちょっと独特な構文を持っていますし、機能も結構多いので「難しそう」と感じてしまう気持ちもわかります。(構…
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita
はじめにみなさんこんにちは!この記事は「必要最小限の努力で最大限実戦で使える知識を提供するRSpec入門記事」、略して「使えるRSpec入門」の第2回です。今回はRSpecのマッチャについて説…

コメント

タイトルとURLをコピーしました