【RSpec3.9】苦手意識克服！一番シンプルな文法で簡単なテストを書いて理解してみよう

## はじめに
これからRSpecを導入しようとされている方の中で、

- テストに対する**抵抗感をなくしたい**
- まずは**簡単なテストの書き方を知りたい**

という方向けに書きました。

RSpecの**超基本文法**とそれを使ったテストの例を以下4つの視点で１つずつ掲載しています。

1. Model
1. Controller
1. View
1. Routing

参考になれば幸いです。

【参考にさせて頂いた記事】
[使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita](https://qiita.com/jnchito/items/42193d066bd61c740612)
[使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5)
[使えるRSpec入門・その4「どんなブラウザ操作も自由自在！逆引きCapybara大辞典」 - Qiita](https://qiita.com/jnchito/items/607f956263c38a5fec24)
[Ruby on Rails のテストフレームワーク RSpec 事始め - Qiita](https://qiita.com/tatsurou313/items/c923338d2e3c07dfd9ee)

## この記事が役に立つ方
- RSpecでテストを書いたことがない方

## この記事のメリット
- RSpecへの抵抗感がなくなる

## 環境
- OS: macOS Catalina 10.15.1
- シェル: zsh
- Ruby: 2.6.5
- Rails: 5.2.3
- RSpec: 3.9.0


## 【事前準備】
今回は**scaffold**を使ったアプリケーションを例にしますので、３ステップで事前準備をしておきましょう。

### 1. scaffoldでアプリケーションを作成しておく

```zsh
$ rails g scaffold user name:string email:string
```

### 2. RSpecをインストールし、テスト用ファイルを作成する

```ruby:Gemfile
group :development, :test do
  gem `rspec-rails`
end
```
↓

```zsh
$ bundle install
```
↓

```zsh
$ rails g rspec:install
```

### 3.テストの実行方法の把握

```zsh
$ rspec
```
上記で全テストが走りますので、テストを書いたら走らせてみましょう。

次に**基本文法**を見ていきます。

## 基本文法

```ruby
require 'rails_helper'

RSpec.describe テスト対象, テストの種類 do
  describe 'テスト対象' do
    it '期待する内容を言葉で書く' do
      期待する動作をコードで書く
    end
  end
end
```

※実際は他に`context`、`before`なども使いますが、本記事では超シンプルなテストを例にします。

**基本文法だけ見てもよく分からない**と思いますので、さっと目を通して以下**具体例**に移りましょう。

## 具体例
MVC+Routingそれぞれに対し、１つずつ**超シンプル**なテストを書いて試していきます。

それぞれ、動作するテストのみ記載していますので、自分でいじってみて**失敗するかどうか**も確認するほうが良いと思います。

### 1.Model
#### バリデーションが正しく動作するかをテストしたい
Userモデルに以下のようなバリデーションがかかっていて、それをテストしたいとします。

```ruby:models/user.rb
class User < ApplicationRecord
  with_options presence: true do
    validates :name
    validates :email
  end
end
```
では、テストを書いてみましょう。
最初に以下コマンドを実行し、テストの雛形を作成しましょう。

```shell
$ rails g rspec:models user
```
`spec/models/user_spec.rb`
が出来ているはずなので、以下のように記述して下さい。

```ruby:spec/models/user_spec.rb                               
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'Userモデルのバリデーションテスト' do
    it 'nameとemailに値があれば有効' do
      user = User.new(
       name: "name",
       email: "sample@example.com"
      )
      expect(user).to be_valid
    end
  end
end
```

#### 【解説】
`User, type: :model`でUser Modelのテストであることを明示。

`user`に適当な名前とメールアドレスを指定してUserモデルから新規インスタンスを作成し、それを`be_valid`というマッチャで有効かどうかを判定しています。

---
### 2.Controller
#### indexアクションで正常にページが表示されるかテストしたい

正常にページが表示されるかは**HTTPレスポンスが200である**と言い換えることが出来ます。

テストを書いてみましょう。
まず先程と同様、以下コマンドを実行します。

```zsh
$ rails g rspec:request users
```
**「あれ？request? controllerじゃないの？」**と思いますよね。

実は、Rails5以降はcontroller_specが非推奨となっています。

controller_specでも書けるのですが、controller関連はrequest_specで記載するのが良いようです。
詳細は下記リンクより。

[RSpec 3.5 がリリースされました！](http://rspec.info/ja/blog/2016/07/rspec-3-5-has-been-released/)

では戻ります。

先程のコマンドで
`spec/request/users_spec.rb`
が出来ているので以下のように記述して下さい。

```ruby:spec/request/users_spec.rb
require 'rails_helper'

RSpec.describe "Users", type: :request do
  describe "GET /users" do
    it "HTTPレスポンスが200になる" do
      get users_path
      expect(response).to have_http_status(200)
    end
  end
end
```

#### 【解説】
`"Users", type: :request`と指定することでUsersのrequest_specであることを明示。

getリクエストで`users_path`(/users)を指定し、それに対するHTTPレスポンスが`response`に入ります。

その`response`に対して`have_http_status`というマッチャで`200`と等しいかを確認しています。

---
### 3.View
#### `<h1>`タグ内が正しく表示されるかをテストする

```ruby:app/views/users/index.html.erb
<h1>Users</h1>
```
`index/html/erb`にはこんな`h1`タグが記載されています。

この`h1`タグ内に表示されている内容が正しく表示されているかをテストしてみましょう。

まずはテスト用のファイルを以下のように作成します。

```zsh
$ rails g rspec:view users index
```

`spec/views/users/index.html.erb_spec.rb`
が出来ているので、以下のように記述して下さい。

```ruby:spec/views/users/index.html.erb_spec.rb
require 'rails_helper'

RSpec.describe "users/index", type: :view do
  describe 'index.html.erbのテスト' do
    it 'h1タグ内にUsersが表示されているかどうか' do
      visit users_path
      expect(page).to have_selector('h1', text: 'Users')
    end
  end
end
```

#### 【解説】
`users/index`の`view`のテストであることを最初に明示。

`visit`の後に`users_path`を指定することで`index.html.erb`にアクセス。

`expect(page)`で今いるページを明示、`have_selector`というマッチャで'h1'に`Users`が表示されているかをテストしています。
...

### ※実は上記テストはうまくいきません。
騙したようで申し訳ありません。テストを実行したら、

```shell
NoMethodError: undefined method 'visit'
```
というエラーが出ませんでしたか？
実は自分もここで手間取りました。

ググるとかなり沢山記事が出てくるので、良くあるエラーなんだと思います。

原因はgem`capybara`がRSpecに読み込まれていないことです。

`visit`は`capybara`の中で定義されている**DSL（ドメイン指定言語）**のため、読み込むために設定を追加しなければいけません。

`spec/spec_helper.rb`
を開いて以下のように**２行**追記して下さい。

```ruby:spec/spec_helper.rb
...略

require 'capybara/rspec' # ここに追記

RSpec.configure do |config|

config.include Capybara::DSL # ここに追記

...略

end


```

この設定で読み込まれる`Capybara::DSL`で定義されているDSL一覧は以下で確認することができます。

もし他に`NoMethodError`が出たら参考にしてみるのも良いかもしれません。

[capybara cheat sheet  · GitHub](https://gist.github.com/zhengjia/428105)

うまくいったら次に進みましょう。

---
### 4.Routing
#### ページのルーティングが正しいかをテストする
最後はルーティングです。

createアクションに対してルーティングがうまくいっているかテストをしてみましょう。

テスト用のファイルはジェネレータを使わなくても作成出来るので、
今回は、手入力でファイルを作成します。

`spec/routing/users_routing_spec.rb`
を新規作成し、以下のように記述して下さい。

```ruby:spec/routing/users_routing_spec.rb
require 'rails_helper'

RSpec.describe "routes for Users", type: :routing do
  describe 'ルーティングのテスト' do
    it 'createアクションのルーティング' do
      expect(post("/users")).to route_to("users#create")
    end
  end
end
```

#### 【解説】
`Users`の`routing`についてのテストであることを明示。

`/users`にPOSTしたら `users`コントローラーの`create`アクションが動くことをテストしています。

## おわりに
いかがでしたでしょうか？

超基本的な内容ではありますが、書くことに対しての苦手意識が少しで減ればいいなと思います。

私も書きながら調べていましたが、検索でヒットする内容には古い情報が多く、苦労しました。

今後も以下最新情報を参照しつつ勉強していこうと思います:point_up:
[RSpec Rails 3-9 - RSpec Rails - RSpec - Relish](https://relishapp.com/rspec/rspec-rails/v/3-9/docs)

## 参考にさせて頂いたサイト（いつもありがとうございます）
[使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita](https://qiita.com/jnchito/items/42193d066bd61c740612)
[使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5)

[使えるRSpec入門・その4「どんなブラウザ操作も自由自在！逆引きCapybara大辞典」 - Qiita](https://qiita.com/jnchito/items/607f956263c38a5fec24)
[Ruby on Rails のテストフレームワーク RSpec 事始め - Qiita](https://qiita.com/tatsurou313/items/c923338d2e3c07dfd9ee)
[全国のSeleniumer必読 - Qiita](https://qiita.com/oh_rusty_nail/items/b8ba525d31ea7c522856)
  [undefined method `visit’ when using RSpec and Capybara in rails](http://stackoverflow.com/questions/15148585/undefined-method-visit-when-using-rspec-and-capybara-in-rails) 
[capybara cheat sheet  · GitHub](https://gist.github.com/zhengjia/428105)