来年に向けて「RSpecのE2Eテスト方法」まとめてみたよ_φ(・・*)

RSepcをつかったModelとControllerの基本的な(ユニット)テストは、
なんとか書けるようになってきましたが、

　「ちゃんとテストやれてる！」

と言えるにはまだまだ、

- インテグレーションテスト
- エンドツーエンドテスト
- 受け入れテスト

色々とやれることはあります。



直近、ユーザーのアクションがより重要なサービスの開発を進めることもあり、
「エンドツーエンドテスト」をやれる良さ気な方法は何か調べてみて、動くまでをまとめてみした。
※結論からいうと、「RSpec ☓ Capybara ☓ Poltergeist」で書くことにした記事です。

## 目次

- [過去記事(RSpec設定/MCtest)](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#%E9%81%8E%E5%8E%BB%E8%A8%98%E4%BA%8B)

- [E2Eテストに何が必要？](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#e2e%E3%83%86%E3%82%B9%E3%83%88%E3%81%AB%E4%BD%95%E3%81%8C%E5%BF%85%E8%A6%81)

- [シナリオ(ステップ)を書くのはどれがいい？](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#%E3%82%B7%E3%83%8A%E3%83%AA%E3%82%AA%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%AE%E3%81%AF%E3%81%A9%E3%82%8C%E3%81%8C%E3%81%84%E3%81%84)

- [js動作のドライブはどれがいいの？](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#js%E5%8B%95%E4%BD%9C%E3%81%AE%E3%83%89%E3%83%A9%E3%82%A4%E3%83%96%E3%81%AF%E3%81%A9%E3%82%8C%E3%81%8C%E3%81%84%E3%81%84%E3%81%AE)

- [E2Eの環境セットアップ方法は？](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#e2e%E3%81%AE%E7%92%B0%E5%A2%83%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E6%96%B9%E6%B3%95%E3%81%AF)

- [feature specの書き方は？](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#feature-spec%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%AF)

- [おわりに](http://qiita.com/hitomi_/items/ca011f63925fc2ef8a37#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB)


## 過去記事

※RSpecの最初のセットアップやModel Controllerユニットテストの
書き方例は下記にまとめてみましたのでよかったら。

- [RSpec テスト環境 設定 メモ _φ(・・*) - Qiita](http://qiita.com/hitomi_/items/fc9e9a3aa68039d68776)

- [RSpec テストコード書き方 サンプル _φ(・・*) - Qiita](http://qiita.com/hitomi_/items/09c3503f06a7a7575b38#_reference-45e0742eb5cdb1bc1bc8)

## E2Eテストに何が必要？

### シナリオ/テストコード
- シナリオが書ける
- シナリオを実行して確認するテストコードが書ける

　→Cucumber, Turnip, RSpec feature spec

### 画面操作
- フォームやボタンを操作できる
- 表示されている画面要素が正しいか確認できる
- 画面遷移が確認できる

　→ Capybara

### js動作

- js動作環境でテストコードが実行できる

　→ selenium, Capybara-webkit, Poltergeist 等

- js動作環境でのテストをheadlessで高速にできるようにする

　→ Capybara-webkit, Poltergeist 等

### デバッグ

- デバッグのためのキャプチャ保存

　→ launchy(Capybaraの依存関係に含まれる), poltergeistのスクリーンショット保存

etc..


## シナリオ(ステップ)を書くのはどれがいい？

ユーザーのシナリオごとにテストコードを書いていくには、色んなライブラリもあったりするようだったので、ざっくり調べてみました。

### Cucumber

https://cucumber.io/

日本語でシナリをを書いて行ける。それを元に実際のテストプログラムfileは別で作成。
変化が激しく、学習コストが高い様子。


### Turnip

https://github.com/jnicklas/turnip

Cucumberの改善としてだされたらしいので、日本語シナリオ使いたいと思ったら、こちらのほうが今は良さそうです。
こちらも日本語でシナリオを書くファイルと、ステップごとに実際のテスコードを書くファイルと分けて書くようです。

※参考
[Rubyist Magazine - エンドツーエンドテストの自動化は Cucumber から Turnip へ](http://magazine.rubyist.net/?0042-FromCucumberToTurnip)


### RSpecの feature specのみ

https://www.relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec

上記のような日本語のシナリオだけをまとめることはせず、
単純にシナリオごとにテストコードを書いていくようです。

### 結論

今関わっているプロジェクトでは、非エンジニア以外にテストシナリオを
説明することはあまりないので、普通にRSpecのfeature specで書いていこうとおもいます^^;


## js動作のドライブはどれがいいの？

### selenium vs Capybara-webkit vs Poltergeist

jsが動く環境での確認をしたいだけなら、seleniumだけで良いようですが、
調べていくと、`Poltergeist`が良さそうでした。

- seleniumは、
　→ブラウザを必要とするため、テストに時間がかかる

- Capybara-webkitは、
　→Qt, xvfb が必要
　 →準備にちょっと色々めんどうそうなのがある


- Poltergeistは、
　→phantomjs を使う
　　→phantomjs入れて gemに書くだけで簡単そう

参考
[poltergeist - Capybaraを使う際に知っておきたいこと - Qiita](http://qiita.com/take/items/779747e0981355e569ad)


## E2Eの環境セットアップ方法は？

上記をふまえて、
「RSpec ☓ Capybara ☓ Poltergeist」が使えるまでを設定してみました。


### Capybara セットアップ

rollback の仕方が変わるそうなので、database_cleanerの設定が必須となるようです。

Gemfile

[jnicklas/capybara](https://github.com/jnicklas/capybara)

```.rb
group :test do
  gem 'database_cleaner', '~> 1.3.0' # テスト実行後にDBをクリア
  gem 'capybara', '~> 2.4.3'         # ブラウザでの操作をシミュレートしてテストができる
```

rails_helper.rb

```spec/rails_helper.rb

require 'capybara/rails'
require 'capybara/rspec'

RSpec.configure do |config|
  config.use_transactional_fixtures = false #trueでいける方法もあるようです

  # 省略

  # テスト実行後にDBをクリア
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation,{:except => %w{categories jobs initials job_positions}})
    DatabaseCleaner.strategy = :transaction
  end

  config.before :each do
    DatabaseCleaner[:mongoid].start
    DatabaseCleaner.start
  end

  config.after :each do
    DatabaseCleaner[:mongoid].clean
    DatabaseCleaner.clean
  end
```
自分は、mongoとmysqlを使っているので上記のように書きました。
他DatabaseCleanerについて詳しくは、下記を
 [DatabaseCleaner/database_cleaner](https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example)


### deviseでのログイン対応

ログイン機能の実装には、お馴染みの `devise ` を使っています。
ログインユーザーを想定して、Capybaraをつかった操作をするには、追加で設定が必要です。


設定追加

```spec/rails_helper.rb

RSpec.configure do |config|
  config.include Warden::Test::Helpers
  # 省略
  config.before(:suite) do
     Warden.test_mode!
     # 省略
  end

  config.after :each do
    Warden.test_reset!
    # 省略
  end

```

spec コードの中で、下記のように書くとログインしたことになる

```spec/features/user_actions_spec.rb
feature "UserActions", :type => :feature do

  context "ログインしている場合" do
    before(:each){
      # devise login
      user = create(:user)
      login_as(user, :scope => :user)
    }
```

※参考
[How To: Test with Capybara · plataformatec/devise Wiki](https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara)


### Poltergeist セットアップ

phantomjs をインストールします
自分の場合は、vagrant CentOSに入れたかったので下記を実行しました

```
$ wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2
$ tar xvjf phantomjs-1.9.8-linux-x86_64.tar.bz2
$ cd phantomjs-1.9.8-linux-x86_64
$ sudo ln -sf "$(pwd)"/bin/phantomjs /usr/local/bin/phantomjs
```


Gemfile

[teampoltergeist/poltergeist](https://github.com/teampoltergeist/poltergeist)

```.rb
  gem "poltergeist" # headlessでjsテストをする(phantomjsが必要)
```

rails_helper.rb

```spec/rails_helper.rb
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
```

あとは、feature specのscenario のoptionに`js: true`をつければjsが動作する&headlessな環境でテスト出来ます。

※参考

- [Functional testing with PhantomJS and CasperJS · TryGhost/Ghost Wiki](https://github.com/TryGhost/Ghost/wiki/Functional-testing-with-PhantomJS-and-CasperJS)

- [RSpec - capybara + Poltergeistでjavascriptをテストするには - Qiita](http://qiita.com/tatsuyard/items/1dee6729228bb1c9073d#_reference-3ffe604ff27c60216c89)

## feature specの書き方は？

### サンプル


```spec/features/user_actions_spec.rb
require 'rails_helper'

feature "UserActions", :type => :feature do

  context "ログインしている場合" do
    before(:each){
      # devise login
      user = create(:user)
      login_as(user, :scope => :user)
    }

    scenario "#btn1ボタンを押すと「詳細ページ」から「作成ページ」へ遷移できる" do
      # 詳細ページへ
      item = create(:item)
      visit item_path(item.seq)

      # ボタンクリック
      find('#btn1').click

      expect(current_path).to eq '/items/new'
    end
  end


  context "ログインしていない場合" do
    scenario "#btn1ボタンを押すとログインモーダルが立ち上がる", js: true do
      # 詳細ページへ
      item = create(:item)
      visit item_path(item.seq)

      # ボタンクリック
      find('#btn1').click

      expect(page).to have_css "div.remodal-wrapper.remodal-is-opened"
    end

    scenario "jsが有効でない場合、#btn1ボタンを押してもremodalが立ち上がらない" do
      # 詳細ページへ
      item = create(:item)
      visit item_path(item.seq)

      # ボタンクリック
      find('#btn1').click

      expect(page).not_to have_css "div.remodal-wrapper.remodal-is-opened"
    end
  end
end

```

実行

```
$ rspec spec/features/user_actions_spec.rb
```


#### 簡単な補足/注意点

- jsが動作する環境でのテストは、`js: true`とします
- pageでCapybaraをつかっていろんな情報が取得できるので `binding.pry`をして
　`ls page`とすると色々便利なメソッドが用意されていることが分かるとおもいます
- Capybaraで、対象のセレクタを指定するときに、同名のClassがあるものを指定するとエラーになります。


### Cabybara書き方参考

Cabybaraでは、こんな時どう書くのか、まとめられた記事がいくつかあって助かりましたm(_ _)m

- [RSpec3 / Capybara / Capybara-Webkit チートシート - Rails Webook](http://ruby-rails.hatenadiary.com/entry/20150103/1420280252)

- [Capybara で同名の CSS セレクタを持つ複数の HTML 要素から任意の要素を見つける | EasyRamble](http://easyramble.com/find-html-element-with-capybara.html)

- [Capybara RSpecでのマッチャ、セレクタ 「こんなときどうするの」その1 - Qiita](http://qiita.com/kenzan100/items/9642615badc3e1cf160a)

### デバッグする

Launchyのおかげで、下記の一行を、確認したい位置(specコード内)に追記すると、
その時点のhtmlを`tmp/capybara`に保存してくれます。

```spec/features/user_actions_spec.rb
 save_and_open_page
```

poltergeistのスクリーンショットを保存する機能を使うこともできるようです

```spec/features/user_actions_spec.rb
page.save_screenshot('/path/to/file.png')
```
https://github.com/teampoltergeist/poltergeist#taking-screenshots-with-some-extensions

参考
[poltergeist - Capybaraを使う際に知っておきたいこと - Qiita](http://qiita.com/take/items/779747e0981355e569ad#2-2)

## おわりに

まだ自分は、エンジニアに本業を絞って２年ですが、
いいシステムを作る&安定した運用には、テストは重要ではないかなと思ってます。

。。そう思いつつ、普段、忙しさに追われたり、テストを書くとはどういうことなのか、
模索しているところではありますが、^^;

目の前に囚われ過ぎない、後のことも考えたシステム作りの文化に貢献できる
エンジニアになってけるようさらに精進してきたいと思います。

2016年も頑張るぞ(*´ω`)ﾉ