自宅待機中に ModelSpec について学習した

新型コロナウィルスの影響で会社から自宅待機を命じられました。

いい機会と思い、ModelSpec について学習したことをまとめました。

### この記事で分かること
- バリデーションテストの考え方
- ModelSpec の基本的な記述の仕方


### この記事でやらないこと
- gem の導入手順
- ModelSpec の説明
- 必要なファイルの準備
- let を使用した変数定義
- FactoryBot や Faker を使用した記述




# 目次

1. 開発環境
2. テストする Model のバリデーション
3. RSpec の雛形を確認
4. context ブロックにテストする項目を書き出す
5. it ブロックに期待する結果を書く
6. it ブロックが叶うように、 context ブロックで御膳立てをする


# 1. 開発環境
```
Rails 6.0.3.4

ruby 2.7.1

rspec-rails 4.0.1
```

# 2. テストする Model のバリデーション


```ruby:app/models/user.rb
validates :name, :account_name, :email, : presence: true
```

今回はこのようなバリデーションをテストしていきます。
「name, account_name, email カラムは必須の項目です」といった内容ですね。

# 3. RSpec の雛形を確認
![EX-IT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660234/968c22c5-71da-0334-4c3e-9590c8a91b56.png)
こちらが RSpec の基本的な形になります。
 ``target`` にはテストしたい内容が入り、〇〇〇にはその結果が入ります。 
 
イメージ的には以下のような感じですね。

```
expect( 1 + 1 ).to eq 2
```
 
 また、``.to`` の直後の ``eq`` はマッチャと呼ばれるもので様々な種類があるのですが、今回は説明を割愛します。詳しくは [こちら](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5#be_xxx-predicate%E3%83%9E%E3%83%83%E3%83%81%E3%83%A3) の記事をご覧ください。
 
 今回は以下の2種類のマッチャを使用します。
 
 ``be_valid`` ... 「バリデーション が適切です」を意味するマッチャ。
 
 ``be_invalid`` ... 「バリデーション が不適切です」を意味するマッチャ。
 
 
 
 それでは実際に ModelSpec を書いていきましょう。
 
# 4. context ブロックにテストの条件を記述する。

 「テストの条件」と聞くと難しく聞こえますが、「正常な場合と異常な場合をそれぞれテストする」と考えても OK です。
 
 これらはそれぞれ「正常系テスト」「異常系テスト」と呼ばれます。
 
 今回の場合だと、正常系テストは
 
 >name カラム、account_name カラム、email カラムが全て指定されている場合
 
 になります。
 
 反対に、異常系テストは
>name カラムが指定されていない場合

>account_name カラムが指定されていない場合

>email カラムが指定されていない場合

になりますね。実際にコードを書いてみましょう。


```ruby
require "rails_helper"

RSpec.describe User, type: :model do
  describe "#validation" do
    # 正常系
    context "name, account_name, email が全て指定されている場合" do
        
      it "" do
          
      end
    end
      
    # 異常系
    context "name が指定されていない場合" do
      it "" do
          
      end
    end
      
      #異常系
    context "account_name が指定されていない場合" do
      it "" do
          
      end
    end
      
    # 異常系
    context "email が指定されていない場合" do
      it "" do
          
      end
    end
  end
end
```

# 5. it ブロックに期待する結果を書く

it ブロックは期待する結果を書く場所でしたね。正常系テストは上手く通ればユーザーが作られる想定なので、そのまま書きましょう。

反対に異常系テストが上手く通るということは、エラー起こるということなので、こちらも同じように書きます。

```ruby
require "rails_helper"

RSpec.describe User, type: :model do
  describe "#validation" do
    # 正常系
    context "name, email, password, account_name が全て指定されている場合" do
        
      it "ユーザーが作られる" do
          
      end
    end
      
    # 異常系
    context "name が指定されていない場合" do
      it "エラーする" do
          
      end
    end
      
      #異常系
    context "account_name が指定されていない場合" do
      it "エラーする" do
          
      end
    end
      
    # 異常系
    context "email が指定されていない場合" do
      it "エラーする" do
          
      end
    end
  end
end
```

さらに、 it ブロックの中身も書いていきましょう。正常系の場合は、以下になります。

```ruby
expect( user ).to be_valid
```

変数 ``user`` に User インスタンスを格納することを想定した記述になっています。この1行で、
>user のバリデーションは適切である

といった意味になります。

異常系テストの場合は以下のようになりますね。

```ruby
expect( user ).to be_invalid
```

それぞれ it ブロック内に記載していきましょう。

```ruby
require "rails_helper"

RSpec.describe User, type: :model do
  describe "#validation" do
    # 正常系
    context "name, email, password, account_name が全て指定されている場合" do
        
      it "ユーザーが作られる" do
    	expect( user ).to be_valid
      end
    end
      
    # 異常系
    context "name が指定されていない場合" do
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
      
      #異常系
    context "account_name が指定されていない場合" do
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
      
    # 異常系
    context "email が指定されていない場合" do
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
  end
end
```

# 6. it ブロックが叶うように、 context ブロックで御膳立てをする
ここまできたら、あとは it ブロック内が実現されるように context ブロック内を埋めていきましょう。まずは正常系テストから。正常系テストの条件は、

 >name カラム、account_name カラム、email カラムが全て指定されている場合
 
 だったので、普通にインスタンスを作成すれば良さそうですね。

 ```ruby
 user = User.new(name: "user", account_name: "user_account_name", email: "user@example.com")
```

次に異常系テストです。一つだけ具体例をみてみましょう。

>name カラムが指定されていない場合

これは name カラムを nil にしてあげれば良さそうです。

```ruby
 user = User.new(name: nil, account_name: "user_account_name", email: "user@example.com")
```

同じ要領で他の異常系テストも記述していきましょう。完成したものが以下になります。


```ruby
require "rails_helper"

RSpec.describe User, type: :model do
  describe "#validation" do
    # 正常系
    context "name, email, password, account_name が全て指定されている場合" do
      user = User.new(name: "user", account_name: "user_account_name", email: "user@example.com")
      it "ユーザーが作られる" do
    	expect( user ).to be_valid
      end
    end
      
    # 異常系
    context "name が指定されていない場合" do
      user = User.new(name: nil, account_name: "user_account_name", email: "user@example.com")
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
      
      #異常系
    context "account_name が指定されていない場合" do
      user = User.new(name: "user", account_name: nil, email: "user@example.com")
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
      
    # 異常系
    context "email が指定されていない場合" do
         user = User.new(name: "user", account_name: "user_account_name", email: nil)
      it "エラーする" do
         expect( user ).to be_invalid
      end
    end
  end
end
```


# 最後に
はい、ここまでお疲れ様でした。

今回の内容はあくまでも初歩的な内容だったかと思います。

今後は FactoryBot や Faker を組み合わせた内容をやっていく予定です。

最後まで読んでいただき、ありがとうございました！