10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rspec createとbuildの違い

Last updated at Posted at 2021-01-22

#目的
・テストコードにおけるcreateとbuildの違いについて理解を深める

#内容

テストコードにおいて下記のコードを実行したら、

pry(#<RSpec::ExampleGroups::User::Nested>)> sign_in(@room_user.user)
NoMethodError: undefined method `user' for nil:NilClass
Did you mean?  super

とのエラーコードが出ました。
userの中身が空ですといった内容のエラーです。コードは正しいと思われるのですが、何故でしょうか。
理由を深掘りしてみます。

user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  before do
    @user = FactoryBot.build(:user)
   #↑ここが原因
  end

  describe 'ユーザー新規登録' do
    it "nicknameとemail、passwordとpassword_confirmationが存在すれば登録できること" do
      expect(@user).to be_valid
    end

    it "nicknameが空では登録できないこと" do
      @user.nickname = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Nickname can't be blank")
    end

    it "emailが空では登録できないこと" do
      @user.email = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Email can't be blank")
    end

    it "重複したemailが存在する場合登録できないこと" do
      @user.save
      another_user = FactoryBot.build(:user)
      another_user.email = @user.email
      another_user.valid?
      expect(another_user.errors.full_messages).to include("Email has already been taken")
    end

    it "passwordが空では登録できないこと" do
      @user.password = nil
      @user.valid?
      expect(@user.errors.full_messages).to include("Password can't be blank")
    end

    it "passwordが5文字以下であれば登録できないこと" do
      @user.password = "00000"
      @user.password_confirmation = "00000"
      @user.valid?
      expect(@user.errors.full_messages).to include("Password is too short (minimum is 6 characters)")
    end

    it "passwordが存在してもpassword_confirmationが空では登録できないこと" do
      @user.password_confirmation = ""
      @user.valid?
      expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password")
    end
  end
end

#buildはデータベースに保存する機能はない
上記、

 @user = FactoryBot.build(:user)

に注目すると、buildメソッドを使用しているが、createにデータベースへインスタンスを保存する役割はありません。
そのため、データベースが空という意味の
`user' for nil:NilClass
が表示されました。

#データを保存する際はcretate
当該部分を正しく訂正すると

@user = FactoryBot.create(:user)

となります。
buildに対してcretateはデータベースへアクセスし、インスタンスを保存する役割があります。

では、buildを使用する理由はなんでしょうか。
buildはデータベースへのアクセスという処理がない分、createよりも処理が早いというメリットがあります。
膨大なデータを扱う際のテストはcreateの必要がない部分はbuildを用いる方が良いでしょう。

#総括
create:DBにインスタンスを保存する
build:メモリに一時的にインスタンスを生成する

テストにおいて、データベースにアクセスする必要がある処理にはcreate。一方、アクセスする必要ないものはbuildを用いる。buildはアクセスがない分、自動化テストの処理が早くなるメリットがある。

10
2
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
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?