【Rails API 入門】RSpec ①

# はじめに
**RSpec**とは、Railsのテストフレームワークの1つです。次のような理由から導入することが望ましい考えています。

- 現場で一番使われている
- 可読性の高い記述ができる
- エラー発生を事前に防ぐことができ、結果的にテストを書く方がコスパがよい
- テスト駆動開発（はじめにテストを書く）が注目されている

最終目標は、Railsで**APIを実装する際のRSpecの使い方**を理解することです！
最後まで頑張って目を通して下さると幸いです！

（昨今のVueやReactなどのフロントエンドフレームワークの普及により、RailsはAPIモードとして、フロントエンドから送られたパラメータを処理し、その結果をJSONレスポンスとしてフロントエンドに返す役割を担うことが多い。）

皆さんがなるべくストレスなく理解できるよう、以下のように順を追って説明します。

1. RSpecを使う上で事前に知っておくこと　→ この記事
- モデルのバリデーションテスト（モデルスペック）→【Rails API 入門】RSpec ②（予定）
- 単体クラスのテスト　→【Rails API 入門】RSpec ③（予定）
- 実装するAPIの処理、レスポンスのテスト（リクエストスペック）→【Rails API 入門】RSpec ④（予定）

# RSpecを使う上で事前に知っておくこと
## `Faker` と `FactoryBot`
### *Faker* とは
**ランダムなデータを、実行するたびに作ってくれるもの**です。

RSpecでは毎回自分でランダムな値を用意するわけにはいかないので、次に説明する`FactoryBot`を含め、これらのgemを使用することが望ましいです。

```rb
Faker::Name.name
=> "Francesco Russel"

Faker::Name.name
=> "Junior Dickinson"
```
このような書き方で、ランダムなデータを毎回作ってくれます。
その他にも、様々な種類のデータを準備することができるので、詳細は[FakerのGitHub](https://github.com/faker-ruby/faker)で調べて見て下さい。
### *FactoryBot* とは
**ダミーのレコードを作ってくれるもの**です（[こちら](https://github.com/thoughtbot/factory_bot_rails)がGitHubページ）。

次のような、商品`Product`モデルのダミーレコード作成を例として説明します。

まずはどのようなダミーレコードを作るのかを`spec/factories`配下にファイルを作成して記述します。

```rb:spec/factories/products.rb
FactoryBot.define do
  factory :product do
    name { Faker::Food.fruits }
    # 略
  end
end
```
すると、次のような書き方をすることで

```rb
FactoryBot.build(:product) # Product.new(name: Faker::Food.fruits)と同じ

=> #<Product:0x0000000000000000
 id: nil,
 name: "Banana",
 created_at: nil,
 updated_at: nil>
```
のようなランダムなデータを作成することができます。
`build`は、`new`を実行する`Product.new(name: Faker::Food.fruits)`と同じ結果を得ることができるということです。

また同じようなやり方で、`Product.create(name: Faker::Name.name)`は

```rb
FactoryBot.create(:product) # Product.create(name: Faker::Food.fruits)と同じ

=> #<Product:0x0000000000000000
 id: 1,
 name: "Lemon",
 created_at: Mon, 04 May 2020 07:30:41 UTC +00:00,
 updated_at: Mon, 04 May 2020 07:30:41 UTC +00:00>
```
のようにレコードを作ることができます。

パラメーターとして**ハッシュ値**を返したい場合は、

```rb
FactoryBot.attributes_for(:product) # { name: Faker::Food.fruits }と同じ

=>{:name=>"Pineapple"}
```
を使用することができます。

ちなみにそれぞれ、`FactoryBot.build(:product)`は

```rb
build(:product)
```
`FactoryBot.create(:product)`は、

```rb
create(:product)
```
`FactoryBot.attributes_for(:product)`は、

```rb
attribute_for(:product)
```

と省略して記載することができます！（**以降はこの省略形で説明します。**）



## `let` と `before`
### *let* とは
**変数を格納するような機能**です。

これを使うことで**可読性が上がる**、**タイポに気づける**等のメリットがあるので、できる限り変数を用意する時は、`let`を使うようにして下さい（詳しい理由は[こちら](https://qiita.com/jnchito/items/cdd9eef2ed193267c651)を参考にして下さい）。

```rb
let(:product) { create(:product) }
=> product # productのインスタンス変数が作られる
```
ここでは、`let`直後の`(:product)`で変数`product`を定義し、`{}`内の`create(:product)`でランダムなレコードを作成しています（`create(:product)`はFactoryBotでランダムなレコードを作成するもので、先程解説した内容です）。

### *before* とは
**テストを行いたい処理の前に行っておきたい処理を書く**ものになります。

例えば、特定の商品（`product`レコード）を所有する`User`（`has_many`や`has_one`リレーション）を事前に作成しておきたい場合は、テストを行う処理の前に

```rb
  before { create(:user) }
```
を記述することで、事前に`User`を作成しておくことができます。

## `subject`
### *subject* とは
**テストしたい処理を明示的に書くもの**で、テストの可読性が向上するものです。

明確に「〇〇処理」を行うテストだよ！と、「主題」（subjectの英語訳）のようにアピールするような役割を持つものです。
後ほど具体例を交えながらの解説を行いますので、ひとまず、**テストしたい処理をsubjectに書く**と覚えて下さい。

```rb
subject { product.valid? }
```
ですのでこれは、`{}`内の`product.valid?`が**テストしたい処理**であり、わざわざ`subject`として切り分けて書くことで、「このテストは`product.valid?`の処理をテストしようとしているんだな！」とレビューする人が判断できるようになります（逆に言えば、subjectがなくても同様のテストを実装することは可能なのです）。

ここで言う`valid?`は`product`インスタンスのバリデーションを実行するメソッドであるので、subjectを使うことで明示的に、「このテストではバリデーションのテストを行いたいのか！」と解釈することができます。

## `expect`
### *expect* とは
expectの英語訳が「期待する」であるように、テストを行うことで**期待される処理**を書くところです。

例えば、

```rb
expect(product.name).to eq "Banana"
```
があるとすると、`expect`直後の`product.name`が`"Banana"`と`eq`（等しい）ことを期待する、確認するという処理になります。

処理結果としては`true`か`false`を返し、`true`であれば**テストの成功**、`false`であれば**テストの失敗**（期待される結果ではない）ということになります。

`eq`は**マッチャー**と呼ばれ、`eq`以外にも様々なものがあります。詳しくは[こちら](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5)を確認して下さい。
# 具体例
商品モデル（`Product`）の`name`カラムのバリデーションのテストを想定しましょう。

次のようなバリデーションが設定してあるとします。

```rb:app/models/products.rb
class Product < ApplicationRecord
  validates :name, presence: true
  # 略
end
``` 
今であれば、何となく、次に示す**`Product`モデルのバリデーションテスト**の内容を理解できるのではないでしょうか？

```rb:spec/models/product_spec.rb
require "rails_helper"

RSpec.describe Product, type: :model do
  describe "バリデーションの確認" do
    subject { user.product.valid? }

    before { create(:user) }

    context "正常なレコードが作られる時" do
      let(:product) { create(:product, user: user) }

      it "商品を登録することができる" do
        expect(subject).to be true
      end
    end
  end
end
```

```rb
RSpec.describe Product, type: :model do
```
まず、`RSpec.describe`後ろの`Product`は、**Product モデルを対象としてテスト**するよという意味合いです（単体クラスのテストでは**Productクラスのテスト**という意味になります）。

その後の、`type: :model`は**モデル**のテストを行うよ！という意味で、
APIのテストであるリクエストスペックの場合は、`type: :request`のように書き、ここではテストの種類を明示します（モデルとは関係のない**単体クラスのテスト**の場合は省略します）。

その次の行は、

```rb
describe "バリデーションの確認" do
```

と書かれてあります。

この`describe`は、テストがどういう内容か？を補足する役割を担っており、その他にも`context`、`it` が存在します。それぞれ、

- `describe`は**テストの対象や行う処理**を表す記述
- `context`は**テストの条件**を示す記述
- `it`は**テスト結果として期待されるもの**を示す記述

を書く必要があります。

これらのテスト内容を補足する役割がある箇所を抜き出すと、

```rb
  describe "バリデーションの確認" do

    context "正常なレコードが作られる時" do

      it "商品を登録することができる" do

      end
    end
  end
```

となり、上から読み解いていくと、

- **テストの対象や行う処理**は`"バリデーションの確認"`で、**テストの条件**として`"正常なレコードが作られる時"`を想定し、**期待される結果**は`商品を登録することができる`であるテスト

の意味になります！

このような理由で、RSpecでは**何をテストしようとしているのか？**を、**視覚的に**理解しやすく、可読性が高いと言われています。


少し前に戻り、先程説明した`describe "バリデーションの確認" do`の次の行、`subject`です。

```rb
subject { user.product.valid? }
```
このように`subject`があることで、このテストでは`user.product.valid?`の処理をテストしたいんだ！
と一目で理解することができます。

ちなみにこの処理はこの時点では実行されません。実行のタイミングは後でやってきます。

そして、その次の処理、

```rb
before { create(:user) }
```
の`before`は、**テストを行いたい処理の前に行っておきたい処理を書く**ものでしたね！
ですので、このタイミングで`user`インスタンスが作られます（UserモデルのFactoryBotが実装されてある想定）。

次の

```rb
let(:product) { create(:product, user: user) }
```
は`let`なので`product`のインスタンス変数を作っていますが、

```rb
create(:product, user: user)
```

の書き方は、この記事で説明した内容より少し発展した`FactoryBot`の使い方です。

これは、先程`before { create(:user) }`で作られた`user`を親として持つ`product`インスタンスを作る、という意味になります。
リレーションが関わるレコードを作るのは頻出なので、合わせて覚えていただけると良いと思います！

そして最後に`it`の中身を解説します。

```rb
it "商品を登録することができる" do
  expect(subject).to be true
end
```

RSpecでは、`it`ブロック内に、**テストとして確かめたい動作コード**を実装し、`it`内が成功すればテストの成功、失敗すればテストの失敗、となります。

```rb
expect(subject).to be true
```
は先程の[**expectとは**](#expect-とは)で説明した通り、

- `subject`の実行結果が、`true`である（`be`マッチャー）か

を結果として期待しています。

それでは`subject`の実行とは何か？それは、先程定義した、`subject { user.product.valid? }`の実行、つまり、

```rb
user.product.valid?
```
であり、`user.product`のバリデーション結果が`true`なのか？それとも`false`なのか？になりますね！

これでやっと、バリデーションのテストが完了したことになります。
（ここまで、大変お疲れ様でした！）

ちなみに、実行結果、つまりターミナルでの出力は、

```rb:terminal
Product
  バリデーションの確認
    正常なレコードが作られる時
　　　商品を登録することができる

Finished in 0.12345 seconds (files took 1.23 seconds to load)
1 example, 0 failures
```
のようになります。

このターミナルの表示を見ると一目でテスト内容が分かり、

- **Product**モデルの**バリデーションの確認**を行っており、**正常なレコードが作られる**と、**商品を登録する**ことができる！

というテスト結果を確認することができます。
（このターミナル表示は`.rspec`ファイルに`--format documentation`を書いて設定しており、出力結果の見た目が良くなるようにしています。）

もしも、`describe "バリデーションの確認"`の記述を省略している場合は、

```rb:terminal
Product
　　正常なレコードが作られる時
　　　商品を登録することができる
```
のような出力結果となり、なんとなくは分かりますが、具体的なテスト内容が分かりません。

このように必要に応じて`describe`や`context`を利用し、テスト結果を誰が見ても分かる状態にするのが理想です！

# 終わりに
RSpecははじめは覚えることが多く、難しいと感じますが、繰り返し実装を行っていくと、頭の整理が付きやすく、スラスラ書けるようになります。みなさんがそのようになれるよう、この記事も改良していければと思います！

近日、【Rails API 入門】RSpec ②〜④を記事として書きます！頑張ります！

# 参考
- [RSpecのletを使うのはどんなときか？（翻訳）](https://qiita.com/jnchito/items/cdd9eef2ed193267c651)
- [使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5)