【前編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた

# はじめに

この記事は、タイトルのとおり、「Everyday Rails」を Rails 6 で勉強したいので、
書籍の翻訳者である伊藤さんのブログを参考にして頑張ってみた記録を記したものである。

記事自体が長くなったので、導入編・前編・中編・後編に分割している。

Rails 6 へのアップグレードは非常に時間がかかるので、いきなり挑戦するのではなく、
まず導入編を読んでいただき、本当に挑戦するのか検討することを強く勧めます。

導入編・中編・後編については、以下を参照すること。

> [【導入編】「Everyday Rails \- RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた \- Qiita](https://qiita.com/miketa_webprgr/items/a93c320fb9e3b4f0b6a5) 
> [【中編】「Everyday Rails \- RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた \- Qiita](https://qiita.com/miketa_webprgr/items/a99dd4cdbf060515ac07) 
> [【後編】「Everyday Rails \- RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた \- Qiita](https://qiita.com/miketa_webprgr/items/08774ecd59b4c208cba9)

また、本記事は、伊藤さんのyoutube動画を見ながら作業した内容の実況中継に
近いような形で書き進めているので、以下を必ず併せて視聴してください。
（youtube動画を視聴している前提で書いているので、この記事単体だと意味が通じない）

> [【前編】永久保存版！？伊藤さん式・Railsアプリのアップグレード手順（youtube動画）](https://youtube.com/watch?v=hT68fhuWbHU)
> [【後編】永久保存版！？伊藤さん式・Railsアプリのアップグレード手順（youtube動画）](https://youtube.com/watch?v=SnwNFMauzjM)

## 作業を始める前に

「Everyday Rails - RSpecによるRailsテスト入門」のサンプルアプリについては、
伊藤さんのyoutube動画を見ながら作業すると、以下のとおりアップグレードできる。

|             | 変更前の環境 | 変更後の環境 |
|:------------|------------:|:------------:|
| Rails       | 5.1.1       | 6.0.0        |
| rspec-rails | 3.8.0       | 4.0.0.beta2(正式版は3.9.0)  |
| Ruby        | 2.4.9       | 2.6.5        |
| その他のgem   | -          | できる限り最新化 |
（2019年10月時点の最新環境）

なお、私は以下のとおりアップグレードした。

なぜと思うところがあるかもしれないが、
初学者なので何となく最新版にしてみたとしか言いようがない。

|             | 変更前の環境 | 変更後の環境 |
|:------------|------------:|:------------:|
| Rails       | 5.1.1       | 6.0.3.2      |
| rspec-rails | 3.8.0       | 4.0.1        |
| Ruby        | 2.4.9       | 2.7.1        |
| その他のgem   | -          | できる限り最新化 |
（2020年6月18日時点の最新環境・・・と思われる）

あと、初学者なので話半分で聞いてもらいたいが、rubyは2.7.1にしない方がよいような気がする。
様々な`gem`との互換性の問題があるためか、警告が大量に出てくる。覚悟して使いましょう。

また、私はヒヨってRailsのバージョンは、6.0.0でよいと思って作業を進めていたが、
`gem 'rails', '~> 6.0.0'`と書いていたので、結果として最新版に更新できていた。  

ブログ内で気になる部分があるかもしれないが、
本人は、Rails 6.0.0 にアップグレードするつもりで頑張っている。

生温かい目で見守ってもらいたい。

## 伊藤さんのyoutube動画の構成

伊藤さんは、ご自身が書いたRailsアプリのアップグレード手順を参考にして、
順を追ってRSpecのサンプルアプリをアップグレードしている。

以下がそのアップグレード手順を記したQiita記事である。

> [永久保存版！？伊藤さん式・Railsアプリのアップグレード手順 \- Qiita](https://qiita.com/jnchito/items/0ee47108972a0e302caf)

この記事では、このアップグレード手順に準拠する形で章立てをする。

##  1. 公式のアップグレードガイドに目を通す

私はほぼ目を通しませんでしたが、通すと勉強になるかと思います。。。

## 2. テストが全部パスすることを確認する

動画では、テストが全てパスするか確認するよう指示が出ている。
RSpecでのテストは以下のコマンドで実行できる。

```
bin/rspec
```

### Specテストでいきなりパスしない！

やってみると、下記の記事で紹介されているようなエラーが出た。  

> [Everyday Railsのセットアップにて、masterブランチのテストを全てパスしたい](https://teratail.com/questions/247071)

どうやら、Rubyのバージョンが問題であるようなので、大人しくRubyを2.4.9に指定することにした。
私は、Rbenvを使っているのだが、使い方を忘れているので、以下を参照して対応した。  

> [Rubyのバージョン変更 \- Qiita](https://qiita.com/pipi_taro/items/9c9a6ccc110b159b967b)

```
# ruby 2.4.9 をダウンロードする
rbenv install 2.4.9

# rubyのバージョンを 2.4.9 に指定する
rbenv local 2.4.9

# rubyのバージョンが 2.4.9 になっていることを確認する
rbenv version
```

無事、Rubyのバージョンを2.4.9に合わせることができた。 

### また、Specテストにパスしない！

RSpecで再テストすると、以下のとおりエラーが出た。  

```
Failures:

  1) Tasks user toggles a task
     Got 0 failures and 2 other errors:

     1.1) Failure/Error: visit root_path
          
          Selenium::WebDriver::Error::SessionNotCreatedError:
            session not created: This version of ChromeDriver only supports Chrome version 81

     1.2) Failure/Error: Unable to infer file and line number from backtrace
          
          Selenium::WebDriver::Error::SessionNotCreatedError:
            session not created: This version of ChromeDriver only supports Chrome version 81
          
Finished in 27.03 seconds (files took 1.18 seconds to load)
70 examples, 1 failure

Failed examples:

rspec ./spec/system/tasks_spec.rb:12 # Tasks user toggles a task
```

Pythonの話がベースだが、以下の記事を参考にした。  
> [seleniumで「Message: session not created: This version of ChromeDriver only supports Chrome version 75」のエラーが表示される場合の対処法 \- Qiita](https://qiita.com/stoneBK7/items/9f258e8ab9ce2d4fa4f5)  

どうやら、私が使っているChromeのバージョンとの不一致が問題である可能性が高い。
Chromeのバージョンを確認すると、以下のとおりバージョンが83だった。  

<a href="https://gyazo.com/4f91e03eada35819ff613bbb192bd365"><img src="https://i.gyazo.com/4f91e03eada35819ff613bbb192bd365.png" alt="Image from Gyazo" width="500" border=1/></a>  

エラーメッセージを見直してみると、Everyday Railsの方ではバージョンが81を要求している。  

ここでバージョンのダウングレードをしてもよいのだが、
そもそもRailsのバージョンを6にアップグレードした際に、
`chromedriver-helper`を`webdrivers`に変更するよう指示が出ているので、
ここはスルーすることにする。  

## 3. 開発用ブランチを作成する

ちょくちょくブランチを切りましょう。
保険は大事です。

## 4. Rails以外のgemをバージョンアップする

さて、指示のとおりブランチを作成した後、Rails以外の`gem`をバージョンアップする。
なお、一度失敗しているので、ここの記述はかなり冗長である。

### 4-a. 最新ではないgemを探す（第１チャレンジ）

`gem`が最新か確認するように指示があるので`bundle outdated`を実行してみる。  

```
outdated gems included in the bundle:
  * actioncable (newest 6.0.3.1, installed 5.1.1)
  * actionmailer (newest 6.0.3.1, installed 5.1.1)
  * actionpack (newest 6.0.3.1, installed 5.1.1)
  * actionview (newest 6.0.3.1, installed 5.1.1)
  * activejob (newest 6.0.3.1, installed 5.1.1)
  * activemodel (newest 6.0.3.1, installed 5.1.1)
  * activerecord (newest 6.0.3.1, installed 5.1.1)
  * activesupport (newest 6.0.3.1, installed 5.1.1)
  * addressable (newest 2.7.0, installed 2.5.2)
  * archive-zip (newest 0.12.0, installed 0.11.0)
  * arel (newest 9.0.0, installed 8.0.0)
  * autoprefixer-rails (newest 9.7.6, installed 6.7.7.2)
  * bcrypt (newest 3.1.13, installed 3.1.12)
  * bindex (newest 0.8.1, installed 0.5.0)
  * bootstrap-sass (newest 3.4.1, installed 3.3.7) in group "default"
  * builder (newest 3.2.4, installed 3.2.3)
  * byebug (newest 11.1.3, installed 9.0.6) in groups "development, test"
  * capybara (newest 3.32.2, installed 2.15.4, requested ~> 2.15.4) in group "test"
  * childprocess (newest 3.0.0, installed 0.8.0)
  * chromedriver-helper (newest 2.1.1, installed 1.2.0) in group "test"
  * cocaine (newest 0.6.0, installed 0.5.8)
  * coffee-rails (newest 5.0.0, installed 4.2.1, requested ~> 4.2) in group "default"
  * concurrent-ruby (newest 1.1.6, installed 1.0.5)
  * crass (newest 1.0.6, installed 1.0.4)
  * devise (newest 4.7.2, installed 4.4.3) in group "default"
  * erubi (newest 1.9.0, installed 1.7.1)
  * factory_bot (newest 5.2.0, installed 4.10.0)
  * factory_bot_rails (newest 5.2.0, installed 4.10.0, requested ~> 4.10.0) in groups "development, test"
  * faker (newest 2.12.0, installed 1.7.3) in group "development"
  * ffi (newest 1.13.1, installed 1.9.18)
  * geocoder (newest 1.6.3, installed 1.4.9) in group "default"
  * globalid (newest 0.4.2, installed 0.4.0)
  * hashdiff (newest 1.0.1, installed 0.3.4)
  * i18n (newest 1.8.3, installed 0.9.5)
  * io-like (newest 0.3.1, installed 0.3.0)
  * jbuilder (newest 2.10.0, installed 2.6.3, requested ~> 2.5) in group "default"
  * jquery-rails (newest 4.4.0, installed 4.3.1) in group "default"
  * launchy (newest 2.5.0, installed 2.4.3, requested ~> 2.4.3) in group "test"
  * listen (newest 3.2.1, installed 3.1.5, requested < 3.2, >= 3.0.5) in group "development"
  * loofah (newest 2.6.0, installed 2.2.2)
  * mail (newest 2.7.1, installed 2.6.5)
  * method_source (newest 1.0.0, installed 0.9.0)
  * mime-types (newest 3.3.1, installed 3.1)
  * mime-types-data (newest 3.2020.0512, installed 3.2016.0521)
  * mimemagic (newest 0.3.5, installed 0.3.2)
  * mini_mime (newest 1.0.2, installed 0.1.4)
  * mini_portile2 (newest 2.5.0, installed 2.3.0)
  * minitest (newest 5.14.1, installed 5.11.3)
  * multi_json (newest 1.14.1, installed 1.12.1)
  * nio4r (newest 2.5.2, installed 2.0.0)
  * nokogiri (newest 1.10.9, installed 1.8.4)
  * paperclip (newest 6.1.0, installed 5.1.0) in group "default"
  * public_suffix (newest 4.0.5, installed 3.0.0)
  * puma (newest 4.3.5, installed 3.8.2, requested ~> 3.7) in group "default"
  * rack (newest 2.2.3, installed 2.0.5)
  * rack-test (newest 1.1.0, installed 0.6.3)
  * rails (newest 6.0.3.1, installed 5.1.1, requested ~> 5.1.1) in group "default"
  * rails-html-sanitizer (newest 1.3.0, installed 1.0.4)
  * railties (newest 6.0.3.1, installed 5.1.1)
  * rake (newest 13.0.1, installed 12.3.1)
  * rb-fsevent (newest 0.10.4, installed 0.9.8)
  * rb-inotify (newest 0.10.1, installed 0.9.8)
  * responders (newest 3.0.1, installed 2.4.0)
  * rspec-core (newest 3.9.2, installed 3.8.0)
  * rspec-expectations (newest 3.9.2, installed 3.8.1)
  * rspec-mocks (newest 3.9.1, installed 3.8.0)
  * rspec-rails (newest 4.0.1, installed 3.8.0, requested ~> 3.8.0) in groups "development, test"
  * rspec-support (newest 3.9.3, installed 3.8.0)
  * rubyzip (newest 2.3.0, installed 1.2.1)
  * safe_yaml (newest 1.0.5, installed 1.0.4)
  * sass (newest 3.7.4, installed 3.4.23)
  * sass-rails (newest 6.0.0, installed 5.0.6, requested ~> 5.0) in group "default"
  * selenium-webdriver (newest 3.142.7, installed 3.6.0) in group "test"
  * spring (newest 2.1.0, installed 2.0.1) in group "development"
  * sprockets (newest 4.0.2, installed 3.7.1)
  * sprockets-rails (newest 3.2.1, installed 3.2.0)
  * sqlite3 (newest 1.4.2, installed 1.3.13) in group "default"
  * thor (newest 1.0.1, installed 0.20.0)
  * tilt (newest 2.0.10, installed 2.0.7)
  * turbolinks (newest 5.2.1, installed 5.0.1, requested ~> 5) in group "default"
  * turbolinks-source (newest 5.2.0, installed 5.0.0)
  * tzinfo (newest 2.0.2, installed 1.2.5)
  * uglifier (newest 4.2.0, installed 3.2.0) in group "default"
  * vcr (newest 6.0.0, installed 3.0.3) in group "test"
  * warden (newest 1.2.8, installed 1.2.7)
  * web-console (newest 4.0.2, installed 3.5.0) in group "development"
  * webmock (newest 3.8.3, installed 3.0.1) in group "test"
  * websocket-driver (newest 0.7.2, installed 0.6.5)
  * websocket-extensions (newest 0.1.5, installed 0.1.2)
  * xpath (newest 3.2.0, installed 2.1.0)
```

悪夢のような数の`gem`が。。。  

ここで激しい勘違いをしていたのだが、`in group development`と`in group test`
のものをまずアップデートしようと伊藤さんは言っているのであって、
それに該当するのが以下の表になるということらしい。  
  
<a href="https://gyazo.com/0174626ff1b1036eb76602f2e54a1bfd"><img src="https://i.gyazo.com/0174626ff1b1036eb76602f2e54a1bfd.png" alt="Image from Gyazo" width="500"/></a>

ちなみに、私はここから明後日の方向に進み出して、最終的に面倒になって、
全ての`gem`のバージョン指定を解除した後に`bundle update`をガツンとしたら、
RSpecで以下のようなエラーが出た。  

```
There is a version mismatch between the Spring client (2.1.0) and the server (2.0.1).

〜  省略 〜

WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. 
Use Selenium::WebDriver::Chrome::Service#driver_path= instead.

〜  省略 〜
```

なお、私はこのフェーズにおいて動画をほぼ見ずに作業をしていた。
**動画は見ましょう、絶対に。**

さて、最初から頑張ってみることにする。  

### 4-a. 最新ではないgemを探す（第２チャレンジ）

ここまでの知見を生かし、Rubyのバージョン指定まで素早くこなす。  

そして素直に、`Gemfile`に`bundle_outdated_formatter`を導入してみる。

指示どおりやっていくと、以下のとおりのエラーが出る。
これは動画でも紹介されているとおりである。

```
Resolving dependencies...
Bundler could not find compatible versions for gem "bundler":
  In Gemfile:
    rails (~> 5.1.1) was resolved to 5.1.1, which depends on
      bundler (< 2.0, >= 1.3.0)

  Current Bundler version:
    bundler (2.1.4)
This Gemfile requires a different version of Bundler.
Perhaps you need to update Bundler by running `gem install bundler`?

Could not find gem 'bundler (< 2.0, >= 1.3.0)', 
which is required by gem 'rails (~> 5.1.1)', in any of the sources.
```

ちなみに、これは先ほど試行錯誤していく中でも出たエラーである。  

私は、エラーメッセージに従う形でbundlerのバージョンを下げたりして、
ゴニョゴニョやっていったが、伊藤さんによると「`bundle update rails`ならいけるっぽい」
ということなので、ここはこのコマンドを試してみる。

やってみると、上手くアップデートできた。
動画では理屈について少し言及していたが、初学者なのでよく分からず。
ここで調べ出すとキリがなさそうなので、次のステップに行くことにした。
  
`bundle outdated fomatter`のコマンドを使って取得した表は、開発環境・テスト環境下で
あるとかそのような状況に関係なく、全ての`outdated gems`を表示する。

そこで、動画の指示のとおり表計算ソフトで加工してみる。
手持ちの`libre office`で加工すると、以下のとおりの表となった。

<a href="https://gyazo.com/45c7d4c9bb04c5e3aa8ce387ecba953b"><img src="https://i.gyazo.com/45c7d4c9bb04c5e3aa8ce387ecba953b.png" alt="Image from Gyazo" width="500"/></a>

何やら、伊藤さんのものと比べて、かなりシンプルなものになった。  

### 4-b. development と test グループの gem を先にアップデートする

`Gemfile`を開き、以下の`gem`のバージョン指定を外してみる。
外すものは、動画で言及されていたものに限定した。  

```
group :development, :test do
  gem 'rspec-rails' # バージョン指定を解除
  gem 'factory_bot_rails' # バージョン指定を解除
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :test do
  gem 'capybara' # バージョン指定を解除
  gem 'selenium-webdriver' # バージョン指定を解除
  gem 'chromedriver-helper'
  # Or use poltergeist and PhantomJS as an alternative to Selenium/Chrome
  # gem 'poltergeist', '~> 1.15.0'
  gem 'launchy'
  gem 'shoulda-matchers',
    git: 'https://github.com/thoughtbot/shoulda-matchers.git',
    branch: 'rails-5'
  gem 'vcr'
  gem 'webmock'
end
```

さて、以下を実行する。  

```
bundle update -g development -g test
```

無事成功した。
ちなみに、動画では`chromedriver-helper`から`webdrivers`に移行するよう指示が出ていた。  

> [サポートが終了したchromedriver\-helperからwebdrivers gemに移行する手順 \- Qiita](https://qiita.com/jnchito/items/f9c3be449fd164176efa)

詳細は動画のとおりだが、`Gemfile`内の`chromedriver-helper`を`webdrivers`に書き換えて、
`bundle install`すればよいらしい。私の場合、`bundle install`は問題なく実行できた。  

さて、RSpecで再テストする。
何やら、エラーが色々と出てきた。  

```
[DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. 
If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` (called at /Users/hogehoge/.rbenv/gems/2.4.0/gems/spring-2.0.1/lib/spring/application_manager.rb:95)
2020-06-17 18:31:22 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.
/Users/hogehoge/.rbenv/gems/2.4.0/gems/factory_bot-5.2.0/lib/factory_bot/definition_proxy.rb:99:in `method_missing': undefined method 'message' in 'note' factory
Did you mean? 'message { "My important note." }'
 (NoMethodError)

〜 以下、省略 〜

```

この記事に詳細があるらしい。

> [【翻訳】factory\_bot 4\.11で非推奨になった静的属性（static attributes） \- Qiita](https://qiita.com/jnchito/items/81637bbdf66c2662eacf)

動画で紹介されているとおり、まず以下を実行する。  

```
gem install rubocop-rspec
```

そして、以下を実行する。

```
rubocop \
  --require rubocop-rspec \
  --only FactoryBot/AttributeDefinedStatically \
  --auto-correct

〜 省略 〜

104 files inspected, 10 offenses detected, 10 offenses corrected
```

RSpecでテストする。
詳細は省略するが、以下の部分だけテストで失敗した。 

```
Failures:

  1) Tasks user toggles a task
     Got 0 failures and 2 other errors:

     1.1) Failure/Error: visit root_path
          
          VCR::Errors::UnhandledHTTPRequestError:

     1.2) Failure/Error: raise VCR::Errors::UnhandledHTTPRequestError.new(vcr_request)
          
          VCR::Errors::UnhandledHTTPRequestError:

```

ただ、このFailuresは動画で紹介されているものである。
詳細は動画で確認してもらいたいが、以下のとおり設定すればテストでの失敗は回避できるらしい。  

```rb
# spec/support/vcr.rb

VCR.configure do |config|
  config.cassette_library_dir = "#{::Rails.root}/spec/cassettes"
  config.hook_into :webmock
  config.ignore_localhost = true
  # 下記の config.ignore_hosts で始まる１行を追加
  config.ignore_hosts 'chromedriver.storage.googleapis.com'
  config.configure_rspec_metadata!
end
```

RSpecでテストする。
すると、何と全てのテストが通る！！！

```
Finished in 9.03 seconds (files took 1.11 seconds to load)
70 examples, 0 failures
```

## どこまで進んだか

動画だと、前編の17分ぐらい経過したところまで進んだ。

> 続編はこちらは
> [【中編】「Everyday Rails \- RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた \- Qiita](https://qiita.com/miketa_webprgr/items/a99dd4cdbf060515ac07)