プロジェクトへテストコードを導入する(環境構築編)

## まえおき
前回は[「計画編」](https://qiita.com/rerere_eng/items/fdf57b817589383db661 "")という事でテスト導入にあたっての目的やテスト範囲の確認などを行った。
今回は「環境構築編」としてRSpecや各種gemのインストールについてまとめていく。

---
### 使用環境とGemについて

---
## 使用環境
- GCE
- OS：CentOS7
- 言語：Ruby(2.2.2)
- フレームワーク：Rails(4.2.5)

---
## 導入するGem
- rspec-rails(4.0.1)
Railsでrspecを実行するために必要

- factory_bot_rails(4.11.1)
テスト用のインスタンスを簡単に、効率よく作成できる

- capybara(2.18.0)
ブラウザをシミュレートしてテストするのに必要

- seleniumu-webdriver(3.141.0)
Webブラウザをプログラムから自動的に操作するためのツール、chromeなどを指定できる

---
## Gemのインストール
①以下をGemfileに記載

```ruby:Gemfile
gem 'rspec-rails'
gem 'capybara'
gem 'selenium-webdriver'
gem 'factory_bot_rails'
```
※デフォルトでFactoryGirlが入っていると競合するので消しておくこと。

②それぞれをバージョン指定でインストールする

```ruby:command
gem install rspec-rails -v 4.0.1
```

いくつか不足するGemがあったので以下順番でインストール。

```ruby:command
gem install nokogiri -v 1.9.1
gem install public_suffix -v 3.1.1
gem install xpath -v 3.1.0
gem install capybara -v 2.18.0
gem install selenium-webdriver -v 3.141.0
```

---
## Gemfile.lockの更新
以下のコマンドでローカルのキャッシュをもとにbundle updateを行います。

```ruby:command
bundle update --local
```

・Gemfile.lock確認
・gem list 確認

```ruby:command
less -f Gemfile.lock | grep rspec
gem list | grep rspec
```

---
### ブラウザテスト周りの設定
---
## Google-chromeのインストール

Google Chromeリポジトリを追加するので下記のコマンドでrepoファイルを新規作成する。

```linux:command
vi /etc/yum.repos.d/google-chrome.repo
```

中身は以下。

```file:google-chrome.repo
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
```

yumでインストールして、バージョン確認。

```linux:command
yum install -y google-chrome-stable
google-chrome --version
=> Google Chrome 87.0.4280.14
```

---
## chrome-driverの設定
ブラウザでテストを実行するためのweb-driverをダウンロードして、解凍、指定ディレクトリに移動してパスを通しておく。
バージョンは先ほど確認したchromeと近いバージョンで同じかできるだけ近いものを指定する。（多少違くても動くようです。）

```linux:command
curl -O -L http://chromedriver.storage.googleapis.com/87.0.4280.88/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
rm chromedriver_linux64.zip
sudo mv chromedriver /usr/local/bin
export PATH="/usr/local/bin:$PATH"

which chromedriver
=> /usr/local/bin/chromedriver

chromedriver -v
=> ChromeDriver 87.0.4280.88 (89e2380a3e36c3464b5dd1302349b1382549290d-refs/branch-heads/4280@{#1761})

```

---
### 各種設定ファイルの記述について

---
## spec_helper.rb

```ruby
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'

Rails.logger = Logger.new(STDOUT)

RSpec.configure do |config|
  # Rspec実行中にエラーが発生した時、実行終了後に赤色でエラー内容を表示する
  config.failure_color = :red

  # Rspec実行中にエラーが発生した時、停止せずに最後までスペックを実行する
  config.fail_fast = false

  # Rspecの実行結果を標準出力へカラーで出力する
  config.color = true

  # Rspecが実行結果を出力する時のフォーマットを指定して見やすくする (Default: :progress)
  config.formatter = :documentation
  
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

end
```

---
## rails_helper.rb

```ruby
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)

# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require 'pp'

# 配下のファイルを全てrequire
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
Dir[Rails.root.join('spec/helpers/**/*.rb')].each { |f| require f }

# テスト実行前にペンディングされているマイグレーションが無いかチェック
ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  # Fixture&Factorybot
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.include FactoryBot::Syntax::Methods
  
  # devise
  config.extend ControllerMacros, :type => :controller
  config.include Devise::TestHelpers, :type => :controller

  # Rspec内でCapybara::DSLを使用出来るようにincludeする
  config.include Capybara::DSL  

  config.use_transactional_fixtures = true  

  config.infer_spec_type_from_file_location!
end
```


---
## factory_bot.rb

```ruby
RSpec.configure do |config|
  # Factory_botを呼び出す際にクラス名の指定を省略できる
  config.include FactoryBot::Syntax::Methods
end
```



---
## capybara.rb

```ruby
require 'selenium-webdriver'
require 'capybara/rspec'

Capybara.configure do |config|
  # DSL Options:
  config.default_driver = :chrome
  config.javascript_driver = :chrome

  # Configurable options:
  config.run_server = true            # ローカルのRack Serverを使用しない (Default: true)
  config.default_selector = :css       # デフォルトのセレクターを`:css`または`:xpath`で指定する (Default: :css)
  config.default_max_wait_time = 15     # Ajaxなどの非同期プロセスが終了するまで待機する最大秒数 (seconds, Default: 2)
  config.ignore_hidden_elements = true # ページ上の隠れた要素を無視するかどうか (Default: true)
  config.save_path = Dir.pwd           # save_(page|screenshot), save_and_open_(page|screenshot)を使用した時にファイルが保存されるパス (Default: Dir.pwd)
  config.automatic_label_click = false # チェックボックスやラジオボタンが非表示の場合に関連するラベル要素をクリックするかどうか (Default: false)
end

Capybara.register_driver :chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--headless') # headlessモードを使用する(無いとエラー)
  options.add_argument('--no-sandbox')

  # セキュリティに影響を及ぼす設定の変更は、アクセス先が安全であることを確認してから行なって下さい。
  # options.add_argument('disable-web-security')      # CORS（Cross-Origin Resource Sharing）を無視する
  # options.add_argument('ignore-certificate-errors') # SSLサーバ証明書のエラーを無視する
  # options.add_argument('disable-popup-blocking')    # ポップアップブロックを無効にする

  options.add_argument('disable-notifications')       # Web通知やPush APIによる通知を無視する
  options.add_argument('disable-translate')           # 翻訳ツールバーを無効にする
  options.add_argument('disable-extensions')          # 拡張機能を無効にする
  options.add_argument('disable-infobars')            # インフォバーの表示を無効にする
  options.add_argument('window-size=1280,960')        # ブラウザーのサイズを指定する
  # options.add_argument('user-agent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"') # IE6

  # ChromeのSPエミュレーションを使用する
  # options.add_emulation(device_name: 'Nexus 5X') # Device Toolbarで選択出来るEmulated Devicesを指定する

  # ダウンロードファイルの保存場所を指定する
  # download_dir = File.join(Dir.pwd, 'files/downloads')
  # FileUtils.mkdir_p(download_dir)
  # prefs = { prompt_for_download: false, default_directory: download_dir }
  # options.add_preference(:download, prefs)

  # Consoleログを取得出来るようにする
  # options.add_preference(:loggingPrefs, browser: 'ALL')

  # ChromeやFirefoxの実行パスを明示的に指定する
  # options.add_option(:binary, '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary')

  # ブラウザーを起動する
  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    options: options)
end
```

---
### 動作確認

---
## テスト実行できるか確認
以下コマンドでテストができることを確認
ここで問題なければrspec単体のテストは実行ができています。

```ruby:command
RAILS_ENV=XXXXX bundle exec rspec

No examples found.
Finished in 0.00029 seconds (files took 0.09507 seconds to load)
0 examples, 0 failures
```

※もし実行するテストを限定する場合はrspecディレクトリ以下のパス指定で可能です。