【Rails】テストの準備からモデル単体テストまで【RSpec】

## はじめに
Railsのテストについて書きます。
RSpecを使ったモデルの単体テストです。バリデーションがうまく働くかどうかを確認することがメインとなります。

## RSpec導入
まずはgemをインストールします。
Gemfileを編集し、bundleインストールしましょう。

```rb:Gemfile
group :development, :test do
  gem 'rspec-rails'
end

# web-consoleというgemがtest環境の中にある場合はdevelopmentのみに移しておく
group :development do
  gem 'web-console'
end
```

```:ターミナル
$ bundle install
```

続いてrspec用のファイルを用意します。

```:ターミナル
$ rails g rspec:install
```
これでいくつかファイルが追加されたと思います。

以下を追加されたファイルの.rspecに追記します。

```:.rspec
--format documentation
```
続いて必要なディレクトリを用意しておきます。

`spec/models`ディレクトリを作成

続いてテストコードを書くファイルを用意したmodelsディレクトリの中に作成します。
今回は`post_spec.rb`を作成することにします。
ファイル名は`モデル名_spec.rb`としましょう。

これで準備はOKです。

## テストコード記述
テストコードを書いてみます。

```rb:spec/models/post_spec.rb
require 'rails_helper' # rails_helperを使うために必要です。何も考えず書いてください
describe Post do # Postモデルについて
  describe '#create' do # createアクションについて
    it "contentがない場合は登録できないこと" do # テストの確認内容を記述
      post = Post.new(content: "") # Postモデルのインスタンス（データ）を作成
      post.valid? # インスタンスを保存する際に、バリデーションにより保存ができない状態であるかを確かめる
      expect(post.errors[:content]).to include("can't be blank") # エラー文に"can't be blank"が含まれるかどうかを判定
    end
  end
end
```

それぞれの処理はコメントアウトで書いたとおりですが、コンソールで一つずつ確かめてみるともう少し理解できると思うので試してみましょう！
ターミナルでコンソール画面を立ち上げてみましょう。

```:ターミナル
$ rails c
```

テストコードの`it 〜　end`を順番に実行してみます。



<img width="691" alt="ff85d977fcb5b51a8144d55c95468715.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605568/137ef78d-2974-bf80-c0bc-8395bf42dc2e.png">
[1]ここでPostモデルのインスタンス（contentカラムが空）が作成されます。
<img width="218" alt="3ce62d1bbec5ec9557a79f44cbc6ab93.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605568/b4abb346-d8b6-1b65-51f1-d9bc8df0e562.png">
[2]上で作成したインスタンスが保存に失敗すればfalseが返ってきます。
valid?やinvalid?メソッドについての詳しい話は[ここ](https://railsguides.jp/active_record_validations.html#valid-questionmark%E3%81%A8invalid-questionmark)を参考にしてください。

<img width="652" alt="67d49b9cce2dfa00427194114ba6a853.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605568/86d471af-cacb-9de9-9379-cbebe0f03850.png">
[3]エラー文はerrorsメソッドを使って見ることができます。
`@message`にエラーメッセージが出ています。
今回Postモデルには空を許さないバリデーションの他に、最低でも２文字というバリデーションも書いてあるので、その２つのエラーが出ています。


## 便利なツール（FactoryBot）
上の例で使ったPostモデルはカラムが少なく、テスト用のデータを作成するのが簡単でした。
しかし、名前やメールアドレス、パスワードなどの複数の情報を持つUserモデルなんかだと、いちいちデータを書いていくのが面倒です。

```rb
user = User.new(name: "hoge", email: "hoge@gmail.com", password: "xxxxxx")
```
このように書かなくてはいけなくなり、冗長なコードになってしまいます。

**FactoryBot**というgemを使えばデフォルトのデータを用意しておき、必要な箇所だけデータを変更して使えるので便利です。
導入方法、使い方を順番に書いていきます。

まずはgemを入れます。

```rb:Gemfile
group :development, :test do
  #省略
  gem 'factory_bot_rails'
end
```

```:ターミナル
$ bundle install
```

`spec/factories`ディレクトリを作成します。

続いてデータを書くファイルを用意したfactoriesディレクトリの中に作成します。
今回は`users.rb`を作成することにします。
ファイル名は`モデル名の複数形.rb`としましょう。
書き方は以下のとおりです。

```rb:spec/factories/users.rb
FactoryBot.define do

  factory :user do
    nickname              {"neko"}
    email                 {"neko@gmail.com"}
    password              {"nyannyan"}
    password_confirmation {"nyannyan"}
    profile               {"hello"}
  end

end
```
factory_botを使うことで、specファイルで簡単にインスタンスを作成できます。

```rb:user_spec.rb
user = FactoryBot.create(:user)
```
と記述するだけでusers.rbで用意したインスタンスを作成してくれます。

実はもう少しだけ簡単に書くことができるのでその設定もしておきましょう。

factory_botの記法の省略
rails_helperに以下のように追記します。

```rb:rails_helper.rb
RSpec.configure do |config|
  # 以下を追記
  config.include FactoryBot::Syntax::Methods
  # (省略)
end
```
これを使って、例えばUserモデルのテストを書いてみます。

```rb:user_spec.rb
require 'rails_helper'

describe User do
  describe '#create' do

    it "nikcnameがない場合は登録できないこと" do
      user = build(:user, nickname: "")
      user.valid?
      expect(user.errors[:nickname]).to include("を入力してください")
    end

    it "emailがない場合は登録できないこと" do
      user = build(:user, email: "")
      user.valid?
      expect(user.errors[:email]).to include("を入力してください")
    end

  end
end
```
このように`build(:モデル名)`とすることでインスタンスを作成できます。
空データなど、factory_botで用意した値と違う値を使いたい場合は、`build(:モデル名, カラム名: 値)`とすればOKです。

## テストの実行
テストを実行するにはターミナルからコマンドを入力するだけでOKです。

```:ターミナル
$ bundle exec rspec  
```
<img width="435" alt="fd3dba157c0da00633c15f6a630b06f2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605568/ada20e9e-276b-9f21-2d13-7ff12a51f0de.png">
テストが通るとこんな感じで表示されます。
失敗すると通らなかったテストの数だけfeiluresの数字がカウントされ、エラー内容が表示されます。

## ファイルを指定してテストを実行
上で書いたコマンド`bundle exec rspec`はspecファイル全てを実行してしまうので、すでに確認済みのテストがある場合は少し無駄が出てしまいます。

```:ターミナル
$ bundle exec rspec spec/ディレクトリ名/ファイル名（_spec.rb）
```
とすることでファイルを指定して実行できます。
今回使用したuserモデルのテストを例にすると以下のようになります。

```:ターミナル
$ bundle exec rspec spec/models/user_spec.rb
```