Turnip の感想

## Turnip とは
feature spec を Gherkin で記述するためのライブラリ
https://github.com/jnicklas/turnip

↓ こんな感じ

```feature
# spec/features/exam.feature
# encoding: utf-8

Feature: テスト管理
  @teachers
  @exams
  Scenario: 学習スケジュールが無い小テストを編集できる
    Given 先生がログインする
    Given 1-1 クラスを用意
    Given 2018-07-01 に小テストを用意
    When サイドバーのスケージュール管理からクラス一覧に移動
    When 1-1 クラスのスケージュールをクリック
    When 2018-07-01 の 1 ~ 20 をクリックする
    Then 学習日が0日と表示されている
    When 編集をクリックする
    When 試験日に 2018-07-01 を入力して更新をクリック
    Then 詳細パネルに 2018-07-01 が日本語表記で表示されている
    Then 学習日が0日と表示されている
```

```rb
# spec/steps/exam_steps.rb
steps_for :exams do
  step ':class_name クラスのスケージュールをクリック' do |class_name|
    school_class = SchoolClass.find_by!(name: class_name)
    within "#cy-school-class-#{school_class.id}" do
      click_on 'スケジュール'
    end
  end

  step ':date の :start ~ :end をクリックする' do |date, start, _end|
    within "#cy-schedule-#{date}" do
      click_on "#{start} ~ #{_end}"
    end
  end

  step '学習日が0日と表示されている' do
    within '#cy-study-schedules' do
      expect(page).to have_content 'テストまでの学習日(0日)'
    end
  end

  step '編集をクリックする' do
    within '.content-wrapper' do
      click_on '編集'
    end
  end

  step '試験日に :date を入力して更新をクリック' do |date|
    fill_in_date_picker('試験日', Time.zone.parse(date).to_date)
    click_on '更新'
  end

  step '詳細パネルに :date が日本語表記で表示されている' do |date|
    within '#cy-exam-detail' do
      expect(page).to have_content Time.zone.parse(date).to_date.strftime('%Y年%m月%d日')
    end
  end
end
```

### Gherkinとは 
feature ファイルの記述方式, 及びそのパーサなどの [gem](https://github.com/cucumber/gherkin-ruby)

もとは [Cucumber](https://github.com/cucumber/cucumber-ruby) で使われていたものが gem に切り出されたらしい

上の例で言うと `test.feature` がそう
`Feature` や `Scenario`, `Given` などの予約語の後に自然言語で定義されてたステップを指定するとそれが実行される
通常の spec ファイルよりも操作の流れがわかりやすく, 非エンジニアでも読むことができる
(正しい解説 -> https://docs.cucumber.io/guides/overview/#what-is-gherkin)


### Cucumberとは

受け入れテストの feature spec を書きやすくするためのオープンソースのもの(java とかでも使えるらしい)
step の定義方法に正規表現を使う
turnip はこれを元につくられた(要出典)

```rb
# steps/teacher_steps.rb
When /^先生がログインする$/ do
  fill_in "Email",    with: @user.email
  fill_in "Password", with: @user.password
  click_button "Sign in"
end
```

`When` や `Then` などの予約語には対応する日本語を使用できる(例↓[出典](https://ruby-rails.hatenadiary.com/entry/20140719/1405777918))
日本語の予約語を使用する場合は実行オプションに `-l ja` を付けるか `# language: ja`をファイルに記述する必要がある

```feature
# language: ja
フィーチャ: ユーザ一覧画面
  シナリオ: ユーザ一覧画面を表示
    前提  ユーザ数が 3 件登録されている
    もし ユーザ一覧画面を表示する
    ならば  1 件のユーザ情報が表示されること
```

```sh
$ cucumber --i18n-language  # 使用できる言語表
$ cucumber --i18n-keywords ja # その言語での予約語の対応表
```

### turnip とは

正規表現の複雑さを排除した cucumber 
capybara と同じ人が開発している[*1](https://github.com/jnicklas)

cucumber と同様に日本語の予約語を使用できる
spec と一緒に実行できる (spec 実行時 `-r turnip/rspec` オプションをつける)




## 導入方法

必要な gem は [turnip](https://rubygems.org/gems/turnip) のみ(ただし, すでにcapybara での feature spec 環境がある前提)

1. `spec/turnip_helper.rb` を用意
1. `spec/features/`に feature ファイル と `spec/steps/` に steps ファイル を用意
1. 実行 `bundle exec rspec -r turnip/spec [feature ファイルパス]` 

###  `spec/turnip_helper.rb` を用意

turnip では rails_helper ではなく turnip_helper を読みに行くので用意
rails_helper に設定を書いている場合は ここで `require`

`Dir[Rails.root.join('spec/steps/**/*_steps.rb')].each { |f| require f }`
は[公式](https://github.com/jnicklas/turnip)では `require` ではなく `load` を使っていますが私の環境だと `hpricot_slate_method_added`で NoMethodError になった後 Segmentation fault でだめでした. (ちゃんとしらべてないので要検証)

```spec/turnip_helper.rb
require 'turnip'
require 'turnip/rspec'
require 'turnip/capybara'
require 'rails_helper'

Dir[Rails.root.join('spec/steps/**/*_steps.rb')].each { |f| require f }
```

###  `spec/features/`に feature ファイル と `spec/steps/` に steps ファイル を用意

一番上の例のように, feature ファイルと steps ファイルを用意する
通常の feature spec の操作一つひとつに名前を付けて step にする感じで良いと思います

一番上の例だとグローバルに step を定義していますが, module でくくってから `RSpec.configure { |c| c.include MonsterSteps }` のように `include` するほうが推奨らしい (要出典)

詳しい下記書き方は [github を参照](https://github.com/jnicklas/turnip)

### 実行 `bundle exec rspec -r turnip/spec [feature ファイルパス]` 

こんな感じに表示される
[![Image from Gyazo](https://i.gyazo.com/7e36b3c89ddaf17894395dd8520e9e2f.png)](https://gyazo.com/7e36b3c89ddaf17894395dd8520e9e2f)


## 考察

### メリット

feature が自然言語で読めるので, ディレクターやマネージャーでもテストケースが確認できる
スプレットシートでテストケースを管理しているようなところでは, feature に落としこんで確認するとかができそう
GUI で確認できたらなお良い(そういうのがあるのかは要調査 (簡単なのならすぐ作れそう?))

TDD がやりやすそう
タスク切る際に, feature だけ作っておいて, 実装者が steps を書くような運用になるのか?(要検討)

すでに feature spec をやっているなら導入が楽
移行も難しくはない

### デメリット

RubyMine で実行(run)できない
これが一番大きい気がする
Cucumber なら実行可能
もちろん RubyMine のコンソールからなら実行可能

変数のコントロールがしにくい
試していないですが, feature では変数を持てない(多分)
上の例のように, step 内で インスタンス変数を作ってそれを回すようなイメージ
feature からは値決め打ちの記述になる (よくある 先に factory で build して値をフォームに入れるようなやり方がしにくい)
ただ, これに関しては feature を読んで何をやっているかわかるためのものなのでそれでいい気がする
(乱数での値生成もやるべきではない?)

結局 capybara の api を使うのでそれからは逃げられない
逆に capybara ができれば大丈夫ということでもある

非エンジニアでもよめるとはいえ github なりでソースを読む必要がある
そういうふうにつかうのであればもう一つなにかをかませる必要がありそう(Web GUI から fearture が閲覧, 編集ができるようにするなど)

## 感想

RubyMine で実行できるなら全力でつかってた