Rspec-rails-テストコードの書き方とmatcherについて

Rails環境における、Rspecを使用したテストコードについて、最近学習したので、備忘録的にまとめます。
誤記などございましたら、ご指摘いただけますと幸いです。

#テストコードとは
まず、テストコードについて説明します。
テストコード
 -「プログラムが意図した通りに動くことを確かめる」ことを目的にテストするためのコード。
 -Rails環境の場合は**Rspec**というGemを使用して確認できます。
＊RSpec
RSpecは、Rubyを元に作成されたテストに特化した言語。「rspec-rails」というGemをインストールすると、RSpecを利用できます。


```:例
Rspec.describe "Calculator" do
  it "1 + 1は2" do
    expect(1 + 1).to eq 2
  end
end
```

**重要：Rspecのヘルパーを使用する際には該当のファイルの冒頭に下記を必ず記入してください**

```:テストファイル
require 'rails_helper'
```

##テストコードを構成する要素
###describe
テストのグループ名をdescribeを使用して定義します。
以下を例にするとCalculatorがこのテストの大枠のグループ名を定義してます。

```:describe
Rspec.describe "Calculator" do
end
```
###example
これから行うテストコードの内容についてタイトルを示しているのが、exampleです。
実際に動作するテストコードについて、タイトルを""の部分に記載します。
以下を例にすると"1+1は２"がこのテストのタイトルとなります。

```:example
it "1 + 1は2" do
end
```

###expectation/matcher
expectationにはテストの内容を記載します。
今回は"expect(1 + 1).to eq 2"の部分がexpectationとなっており、以下のように記載します。
ここで出てきた"eq"の部分を、matcherと言います。
それでは以下にてmatcherの種類を一部まとめていきます。

```:expectation/matcher
expect(1 + 1).to eq 2
```

##matcherの種類と使い方
matcherには複数種類がございます。ここでは一部について記載いたします。
###eq
eqは、以下例における"X"と"Y"が等しいかチェックするmatcherです。

```:例
expect(X).to eq Y
```
###include
引数にとった値がexpectの引数である配列に含まれているかをチェックすることができるmatcherです。
以下例では、ユーザー登録時に必須のemailを入れていない場合をテストしてます。
この場合、「nicknameが空の場合はcan't be blankというエラーが出るはずだ」と推測できるため、include("can't be blank")のように書きます。
*"can’t be blank”は、元々RailsのGemで用意されているエラーメッセージです。

```:例
expect(user.errors[:email]).to include("can't be blank")
```
###be_valid　(predicate matcher)
expectの引数にしたインスタンスが全てのバリデーションをクリアする場合にパスするmatcherです。
*バリデーションは書くモデルファイル内に記載します。

```:例
expect(user).to be_valid
```
###be_a_new
対象が引数で指定したクラスのインスタンスかつ未保存のレコードであるかどうか確かめることができます。

```:例
expect(assigns(:message)).to be_a_new(Message)
```
上記コードは、assigns(:message)がMessageクラスのインスタンスかつ未保存かどうかをチェックしています。
*assignsメソッド:コントローラーのインスタンス変数をテストするメソッド。
引数にインスタンス変数をシンボル型で渡します。

###render_template(viewのチェック）
引数にアクション名を取り、引数で指定されたアクションがリクエストされた時に自動的に遷移するビューを返します。
"基本的にexpect(response).to"と共に使用します。
*response:example内でリクエストが行われた後の遷移先のビューの情報を持つインスタンス

```:例
expect(response).to render_template :index
```


###redirect_to(コントローラのチェック）
引数に対するリダイレクトした際の情報を返すmatcherです。
redirect_toの後に移行先の情報を記載します。
"基本的にexpect(response).to"と共に使用します。

```:例
expect(response).to redirect_to(new_user_session_path)
```

###change
引数が変化したかどうかを確かめるために利用できるmatcherです。

```:例
expect { do_something }.to change(object, :attribute)
```
例えば、change(Message, :count).by(1)のように記載すれば、メッセージの数が１個増えたか確認でき、メッセージ作成時に、しっかりとレコードに保存されているかテストできます。


###その他matcher
下記URLが参考になると思います。
https://relishapp.com/rspec/rspec-rails/v/3-9/docs/matchers
https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers

##その他（メモ）
###letメソッド
letメソッドはRspecのヘルパーメソッドの一つで、値を同一example内で記憶しておき、何度も同じ値を返します。
＊exampleが異なる場合は、この限りではありません。
＊遅延評価（lazy-evaluated)
:letメソッドは呼び出されるまで実行されず、初回のみ実行されます。
let!を使用することで、強制的に各exampleの前に実行することができます。
また、上記letメソッドに対してbeforeメソッドは各exampleの実行前に毎回処理を行います。

```:例
describe MessagesController do
#  letを利用してテスト中使用するインスタンスを定義します。
  let(:user) { create(:user) }
```

以上となります。最後までご覧いただき、ありがとうございました！
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします！
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。

##参照
Rspec rails README
https://github.com/rspec/rspec-rails/blob/master/README.md

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
https://qiita.com/jnchito/items/42193d066bd61c740612