Railsでrspecを使うように設定する

単純なメモのみです。

### やりたいこと

- [Railsチュートリアル](https://railstutorial.jp)や新規のRailsアプリケーションで、rspecを使うようにしたい

### なぜrspec?

#### 組み込みのminitestではだめなの?

デフォルトでは、rails newした際には、テスト用のフレームワークとしてMinitestが最初から利用できるようになっています。
(参考: [Rails テスティングガイド](https://railsguides.jp/testing.html))


参考にさせていただいている[Railsチュートリアル](https://railstutorial.jp)でも、現時点（第4版）でもテストはMinitestを使った形式で解説されています。

以前はrspecだったようですが、rspecは学習コストも高いとのことで標準のMinitestに切り変えたそうです。
（参考: [Railsチュートリアルの歩き方(第4版)](https://www.slideshare.net/yasulab/railstutorialjp-4e))


個人的には、お世話になっているRedmineのテストがMinitestが中心なため、特にこれといった準備の要らないMinitestが好きだったりします。


#### きっかけは現場がそうだったから

ただ、現場でrspecしかいじっていなくてよく分からない / rspecを勉強しないといけない...といったケースが出てきましたので、だんだんとrspecを使うようになって来ました。

そんなこんなで、まずはrspecを使えるようにしてみます。

### Gemfile調整とBundle install

まずはお約束のrails new などでアプリケーションの雛形を作ります。
その後での作業になります。

※ rails newする時に、「後でrspecにするから標準のテストは要らない！」という場合は、”-T” オプションを付けるとテスト作成をスキップしてくれます (20170613:追記)

Gemfileのdevelopment, testの箇所に rspec-rails を追加します。
（この例ではバージョンを固定していません）

rspecのgemが必要なのは、開発/テスト環境のみ。
本番にデプロイする際には必要なければ、group のブロックの中に入れておきます。

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

設定を追加したら、bundle install します。

- この例では、通常はシステムのgemと混ざらないように--path指定でアプリケーションの直下にgemをinstallしています
- Deploy先（production）は今のところ無いのとproductionではテスト関連のものは使わないので、--without production を指定

```
$ $ bundle install --without production --path=vendor/bundle
```

### 基本の設定

rspecもrailsのジェネレータを使って基本設定を作ります。
（rspec --initだと、rails_helper.rbができません）

```
$ bundle exec rails g rspec:install
Running via Spring preloader in process 49348
   identical  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb
      
$ tree spec/
spec/
├── rails_helper.rb
└── spec_helper.rb

0 directories, 2 files      
```

#### からっぽでも試す

rspecコマンドで、spec/ 以下のテストが実行されます。
rspecの実行タスクは、標準でRake taskが用意されているので、そちらからの実施でも大丈夫です。

テストはまだ無いので、結果は空っぽです。


```
$ bundle exec rspec
No examples found.


Finished in 0.00066 seconds (files took 0.19928 seconds to load)
0 examples, 0 failures

# rake taskでの呼び出し（オプション指定できない）
$ bundle exec rake spec
No examples found.


Finished in 0.00104 seconds (files took 0.22282 seconds to load)
0 examples, 0 failures

```
(※ Rails5だと、rake specでもrails specでもどちらでも大丈夫です）

### 既存のモデルにspecを追加する

rspec-railsのジェネレータを使って、各specの雛形を作ります。

- オプションはこちら: [rspec-rails / Generators](https://relishapp.com/rspec/rspec-rails/docs/generators)

まずは既存のモデルのspecを追加してみます。

```
# チュートリアルで作ったモデル：Userのテスト追加
$ bundle exec rails generate rspec:model User
Running via Spring preloader in process 49957
      create  spec/models/user_spec.rb
      invoke  factory_girl
      create    spec/factories/users.rb


# 上記で作ったテストの実行
$ bundle exec rspec spec/models/
*

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) User add some examples to (or delete) xxxxx/toy_app/spec/models/user_spec.rb
     # Not yet implemented
     # ./spec/models/user_spec.rb:4


Finished in 0.00145 seconds (files took 4.32 seconds to load)
1 example, 0 failures, 1 pending

```

オプションにあったscaffoldも試してみます。
ルーティングやコントローラのspecが追加されます。

```
$ bundle exec rails generate rspec:scaffold User
Running via Spring preloader in process 49784
      create  spec/controllers/users_controller_spec.rb
      create  spec/views/users/edit.html.erb_spec.rb
      create  spec/views/users/index.html.erb_spec.rb
      create  spec/views/users/new.html.erb_spec.rb
      create  spec/views/users/show.html.erb_spec.rb
      create  spec/routing/users_routing_spec.rb
      invoke  rspec
      create    spec/requests/users_spec.rb
```

ひとまずこんな感じで、rspecを使う準備ができました。

### 中身を見てみます

modelに対するspecは、"pending" でほとんど内容はありません。
railsのgeneratorで作ったモデルもまだメソッドが何もないので、そちらに合わせて自分で処理を書いていく感じになります。

controllerに関しては、railsのgeneratorでの作成段階で、CRUDの標準的なメソッドが一式追加されるので、それに合わせてspecも基本的なテスト項目が生成されています。（便利！）

```
  # users_controller_spec.rb の抜粋
  describe "GET #index" do
    it "assigns all users as @users" do
      user = User.create! valid_attributes
      get :index, params: {}, session: valid_session
      expect(assigns(:users)).to eq([user])
    end
  end

  describe "GET #show" do
    it "assigns the requested user as @user" do
      user = User.create! valid_attributes
      get :show, params: {id: user.to_param}, session: valid_session
      expect(assigns(:user)).to eq(user)
    end
  end

```

あとは頑張ってテストの内容を少しずつ増やしていく形になります。


### まとめ

以上、またもや拙いメモですが、こんな流れとなりました。

- Railsの基本はMinitestの環境が用意されている
- どうしてもrspecに揃えないといけない場合は追加のgem, 設定が要る



#### 参考にしているサイト

rspecはまだまだ勉強中ですが、マッチャー（期待している文字列が結果に含まれているかどうか）は良く参照しますので、なんだかんだでこちらを良く見ています。

- [Rspec](http://rspec.info)
- [Rspec Documentation (Relish) ](https://relishapp.com/rspec/)


また、おかげさまで、rspecに関する情報はとてもたくさんあることと、現場でのまわりの皆さんの書き方やオープンソースのアプリケーションの書き方を眺めながら、なんとか進めている感じです。


#### memo: Relishについて

rspec-coreのドキュメントは、http://rspec.info ではなくRelishというドキュメンテーション用のサイトで公開されています。

rspec-coreのソースコードのうち、Cucmberで書かれたfeatures/ ディレクトリ一式がそのままドキュメントに変換されて公開されているみたいです。
Relishへのサイトへのドキュメントの反映を実施するために、relishというgemがあります。rspec-coreのrake taskには、この操作を行うtaskも用意されています。

もちろん、 https://github.com/rspec/rspec-core を手元にcloneしてきて、featuresのテスト(cucumber) を走らせることもできます。

```
# 実行例
$ bundle exec cucumber features/command_line/dry_run.feature 
Using the default profile...
.....

1 scenario (1 passed)
5 steps (5 passed)
0m1.050s

```

Cucumberに関してはまだまだ追いついていないので、完全に脱線です...。