RSpec単体テストの基礎を身につける。（モデル編）

今回はRSpec初学者の方がRailsアプリケーションのテストの際にRSpecを使用してモデルの単体テスト行う事を想定して記事を書きあげました。

モデルはアプリケーションのコアとなる部分になるため、モデルのテストは大変重要な工程になります。
しかしテストを学習し始めたばかりの頃は、テストって何を書いたら良いのか分からないという事もあるかと思います。
そんな時は次のような事を中心にテストを作成してみると良いかもしれません。


1. 有効な属性で初期化された場合は、モデルの状態が有効(valid)になっていること

1. バリデーションを失敗させるデータであれば、モデルの状態が有効になっていないこと 

1. クラスメソッドとインスタンスメソッドが期待通りに動作すること

今回はこの3点のポイントに沿って実際にテストコードを書いていきたいと思います。

まずはユーザー登録機能をもったUserモデルの単純なテストコードです。

```ruby:user.rb(モデル用ファイル)

class User < ApplicationRecord
devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

validates :nickname presence: true

has_many :tweets

・・・省略
end

```
※deviseのvalidatableモジュールによりメールアドレスとパスワードに関して必要な全ての検証を作成されます。
検証内容としては、メールアドレスが存在すること、ユニークであること、形式が有効であること。パスワードに関しても存在すること、長さなどが検証対象です。

```rb:user_spec.rb（テスト用ファイル）
require 'rails_helper'
RSpec.describe User, type: :model do

　# beforeメソッドでユーザーのインスタンスを予め用意
  before do
    @user = User.new(
      nickname: "Taro",
      email: "rspectest@.com",
      password: "rspec1111",
      password_confirmation: password
    ) 
  end

  describe User do
    # ニックネーム、メールアドレス、パスワードがあれば登録できること
    it "is valid with a nickname, email, and password" do
      expect(@user).to be_valid
    end

    # ニックネームがなければ無効な状態であること
    it "is invalid without a nickname" do
      @user.nickname = ""
      @user.valid?
      expect(@user.errors[:nickname]).include("can't be blank")
    end

    # メールアドレスがなければ無効な状態であること

    it "is invalid without an email address" do
      @user.email = ""
      @user.valid?
      expect(@user.errors[:email]).include("can't be blank")
    end

    # パスワードがなければ無効な状態であること do
    it "is invalid without an password" do
      @user.password = ""
      @user.valid?
      expect(@user.errors[:password]).include("can't be blank")
    end

　　# 重複したメールアドレスで登録すると無効な状態であること
   it "is invalid with a duplicate email address" do
     @user.save
     another_user = User.new(
       nickname: "Jiro",
       email: "rspectest@.com",
       password: "rspec2222",
       password_confirmation: password
     )
     another_user.valid?
     expect(another_user.errors[:email]).include("has already been taken")
   end
  end
end

```

上記のテストで以下の部分のことが正しいかどうかをテストしました。

- 有効な属性で初期化された場合は、モデルの状態が有効(valid)になっていること（ニックネーム、メールアドレス、パスワードがあれば登録できること）

- バリデーションを失敗させるデータであれば、モデルの状態が有効になっていないこと （その他のテスト部分）


最後に投稿用のTweetモデルとしてクラスメソッドのテストを書いてみます。

```rb:tweet.rb(モデル用ファイル)

belongs_to :user

# 投稿検索用のメソッド
def self.search_by_tweet(search)
    return Tweet.where("content LIKE ?", "%#{search}%")
end

・・・省略

```

```rb:tweet_spec.rb(テスト用ファイル)

require 'rails_helper'
RSpec.describe Tweet, type: :model do

  # 検索文字列に一致する投稿を返すこと
  it "returns tweets that match the search term" do
    user = User.create(
      nickname: "Taro",
      email: "rspectest@.com",
      password: "rspec1111",
      password_confirmation: password
    )

    tweet = user.tweets.create( content: "success", user: user)

    expect(Tweet.search_by_tweet("success")).to include(tweet)
    expect(Note.search_by_tweet("hoge")).to_not include(tweet)
  end
end

```
こちらでモデルで定義したクラスメソッドが機能しているかどうかをテストしました。
他にもたくさんテストすべき箇所はたくさんありますが、今回はモデル単体テストの全体イメージを掴むことを目的とした為、大部分を省略させて頂いて頂きました。

最後まで当記事を読んで頂きありがとうございました。