だれがなんといおうとぼくこそさいきょうのRails4テストかんきょう（ｒｙ

（※以下の記事はもう古く、Rails4.1時代に追従できていません。他の先輩諸氏の記事を参考にしてください）

## はじめに懺悔します

最強とかウソです。釣りです。すみませんすみませんすみません。

これくらい、みなさんやってますよね。でも、慣れてない人とかいると思いますし、なにがしかの参考になればと思って私の設定を晒します。

## 導入する項目

本記事で導入するテスト関連のGemは以下の通りです。フフフ、圧倒的じゃないか、我が軍は。

* RSpec　（BDD環境）
* Cucumber　（受け入れテスト環境）
* Guard　（ファイル変更を監視して、テストを自動化）
* Spring　（テスト高速化。テスト以外にもrails gとかrails consoleとか色々高速化してくれる）
* Factory Girl　（標準のフィクスチャに不満を感じる全ての方に）
* Database Cleaner　（テストのたびにDBをキレイに）
* Capybara　（Webブラウザによるアクセスをシミュレートするテストを実現）
* coffee-rails-source-maps　（CoffeeScriptのソースマップを出力する）

## 以下、手順

### rbenvでRuby2.0をインストールする。

詳しい手順は、私の書いた[この記事](http://qiita.com/emadurandal/items/a60886152a4c99ce1017)を参考にしてください。

### Rails4.0のローカルインストール

同じく、私の書いた[この記事](http://qiita.com/emadurandal/items/a60886152a4c99ce1017)を参考にしてください。

```bash
$ cat << EOS > Gemfile
source "http://rubygems.org"
gem "rails", "4.0.0"
EOS
```

```bash
bundle install --path vendor/bundle
```

### プロジェクト生成

```bash
$ bundle exec rails new MyProject -d postgresql --skip-test-unit --skip-bundle
```

`--skip-test-unit`をつけることで、Rails標準のTest::Unit 関連の設定やファイルの生成を行わないようにします。
また、`--skip-bundle`によって、プロジェクト生成時の`bundle install`の発動を抑止します（後に`bundle install --path vendor/bundle`したいため）。
-dオプションは、使用するデータベースを指定するものです。MySQLの場合は`-d mysql`。何もつけなければ標準のSQLiteです。ここらへんはお好みで。

### Gemfileの編集

以下に全文を晒しますが、`group :development do ~ end` と `group :development, :test do ~ end` のところだけ追記すればOKです。

```rb:Gemfile
source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.0'

# Use postgresql as the database for Active Record
gem 'pg'

# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'

# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'

# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'

group :doc do
  # bundle exec rake doc:rails generates the API under doc/api.
  gem 'sdoc', require: false
end

group :development do
  gem 'coffee-rails-source-maps' # CoffeeScriptのソースマップを出力するために必要
end

group :development, :test do
  gem 'spring'
  gem 'rspec-rails'
  gem 'cucumber-rails', require: false, git: 'https://github.com/cucumber/cucumber-rails.git'
  gem 'factory_girl_rails'
  gem 'database_cleaner', github: 'bmabey/database_cleaner'

  gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i # OSXの場合のみ、ファイル変更検知のため（それ以外の環境ではポーリングになる）
  gem 'guard-rspec'
  gem 'guard-cucumber'
  gem 'guard-coffeescript' # app/assets以下はRailsが自動的にコンパイルしてくれるが、テスト用コードは対象外なので、これを入れる

  gem 'capybara', git: 'git://github.com/jnicklas/capybara.git'
end


# Use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'

# Use unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano', group: :development

# Use debugger
# gem 'debugger', group: [:development, :test]
```

ところどころgit指定しているのは、通常のバージョンではまだ互換性の問題を抱えていたりして、現時点ではエラーが起きるためです。そこでgitリポジトリから問題が解決されているであろう最新のmasterの内容を取ってきて、対応します。
そのうち、git指定なくても良くなるかもしれませんね。

### Gemfileで指定したgemのインストール

`--path vendor/bundle` を指定することで、プロジェクト内に閉じた形でGemをインストールできます。たまにこれをやってない人がいますが、今や常識ですので覚えましょう。

```bash
$ bundle install --path vendor/bundle
```

なお、現時点では`nokogiri`というGemがおそらくバージョン1.6.0以降のものがインストールされると思いますが、このインストール処理で、「固まったか！？」というくらい待たされます。
原因については[こちらの記事](http://qiita.com/suu_g/items/fcf549e16c797a9d7dc0)を参照してください。まぁ、辛抱強く待つか記事中の回避策をとられるかはお任せします。

### テスト環境のセットアップ

#### RSpecのインストール

```bash
$ bundle exec spring rails g rspec:install
```

エラーが出ないか確認

```bash
$ bundle exec spring rspec
 
No examples found.


Finished in 0.0001 seconds
0 examples, 0 failures
```

rails g コマンドでモデルやコントローラを作成したときに、同時にRSpecのファイルも生成されるように設定します。
config/application.rb に次の記述を追加します。

```rb
    config.generators do |g|
      g.test_framework = "rspec"
    end
```

念のために、config/application.rbの全文を晒しましょうか。

```rb:config/application.rb
require File.expand_path('../boot', __FILE__)

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)

module MyProject
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de

    config.generators do |g|
      g.test_framework = "rspec"
    end
  end
end
```

#### cucumberのインストール

```bash
$ bundle exec spring rails g cucumber:install
```

エラーが出ないか確認

```bash
$ bundle exec spring cucumber

Using the default profile...
0 scenarios
0 steps
0m0.000s
Run options: --seed 28489

# Running tests:



Finished tests in 0.002694s, 0.0000 tests/s, 0.0000 assertions/s.
```

#### Guardの初期設定

Guardfile生成

```bash
$ bundle exec guard init
````

Guardfileにspringを使うために、記述を修正する。

```rb
guard 'cucumber', command_prefix: 'spring', bundler: false do
```

```rb
guard 'rspec', spring: true do
```

また、テスト用CoffeeScriptコード用の設定を記述する
すでに記述されている `guard 'coffeescript', :input => 'app/assets/javascripts'` はコメントアウトする。

```
# guard 'coffeescript', :input => 'app/assets/javascripts'

guard 'coffeescript', output: 'spec/javascripts/compiled' do
  watch(%r{^spec/javascripts/(.*).coffee})
end
```

#### Factory Girlの設定

spec/spec_helperに以下を追加。

```rb
require 'factory_girl_rails'
```

features/support/env.rbに以下を追記。

```rb
require 'factory_girl_rails'
```

テストの際にテストデータがちゃんと読み込まれるように、 spec_helper.rb に以下を追記。

```rb
config.before(:all) do
  FactoryGirl.reload
end
```

これで設定は終わりです。お疲れ様でした。

## じゃ、テストするぞー。

次のように、Guardを起動すれば……。

```bash
$ bundle exec guard
05:54:31 - INFO - Guard is using TerminalTitle to send notifications.
05:54:31 - INFO - Running all features
Disabling profiles...


0 scenarios
0 steps
0m0.000s

05:54:36 - INFO - Guard::RSpec is running
05:54:36 - INFO - Guard is now watching at '/Users/smith/dropbox/Program/MyProjects/'
[1] guard(main)>
```

途中でエラー（スタックトレースなど）が出ずに、最後に、`guard(main)>` というプロンプトが出ればOKです。
もし、エラーが出てしまった場合は、guardやspring、cucumber、RSpecなどのバージョン間の互換性がとれていない場合があります。ググると大抵、各プロジェクトのgithubのIssueとかで似たようなトラブル報告が引っかかるので、それを参考に対処しましょう。

さて、無事にプロンプトが出たと仮定しますが、使い方が分からない場合は、とりあえず`help`と入力しましょう。また、何も入力せずにリターンキー（エンターキー）を押すと、全てのテストを強制実行します。Guardを停止したい場合は`quit`と入力します。

Guardの起動中は、Guardがコンソールを占有するので、他にコマンドラインで作業したい場合は別のコンソールを立ち上げましょう。

さて、これでRSpecやらCucumberやらのファイルを追加・修正するたびにテストが走ります。もうやめられませんね。これは。

## CoffeeScriptによるJavaScriptテストについて

今回は人の好みがあると思ってあえて紹介しませんでしたが、JavaScriptのテストも重要ですね。
JasmineとかMochaとか。ググればRails用のGemの紹介記事が見つかると思います。

で、JavaScriptのテストコードですが、やはりCoffeeScriptでスッキリ書きたいものですね。
先ほどの以下の設定により、CoffeeScriptで書いたテストファイルの修正をGuardが検知して再コンパイルしてくれます。
ちなみに以下の設定はJasmine用ですが、Mochaの場合とか、必要に応じて書き換えてください。

```rb
guard "coffeescript", output: "spec/javascripts/compiled" do
  watch(%r{^spec/javascripts/(.*).coffee})
end
```

あと、テストというよりデバッグですが、coffee-rails-source-mapsを入れているおかげで、Development環境では常にCoffeeScriptのソースマップが生成されます。Chromeなどでソースマップを有効にしていれば、CoffeeScriptのままステップ実行したりできます。

## FactoryGirlの使い方について

一番は[公式の情報](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md)を読むことでしょう。一番詳しく書いてあります。が、ちょっと説明が簡素すぎますね。

こちらの[サイト様](http://blog.livedoor.jp/sasata299/)の記事でも分かりやすく解説されていますね。
[factory_girl で最低限知っておきたい4つの使い方](http://blog.livedoor.jp/sasata299/archives/51931175.html)

また、テストの時だけでなく、開発時にデータ投入したい場合にもFactoryGirlを使うことができます。

Railsコンソールを起動して、

```bash
bundle exec spring rails console
```

FactoryGirlの機能を呼べば良いのです。

```irb
irb(main):1:0> FactoryGirl.reload
irb(main):2:0> 10.times { FactoryGirl.create(:foo) }
```

便利ですね。しかし、FactoryGirl……工場娘ですか。なかなか良い響きですね（何が

## その他トラブルシューティング

### プロジェクトのフォルダ名やパスを変更するとRspecでnokogiri関連のエラーが発生する。

　→フォルダ名・パスを元に戻すか、vendor/bundleディレクトリを削除して、bundle updateしなおす。

### $ bundle exec spring rspecした際に、以下のようなエラーが起きた場合。

```
/Users/smith/dropbox/Program/RailsProjects/MyProject/01_Development/xxxx/yyyy/zzzz/MyProject/vendor/bundle/ruby/2.0.0/gems/spring-0.0.10/lib/spring/server.rb:40:in `initialize': too long unix socket path (117bytes given but 104bytes max) (ArgumentError)
```

プロジェクトの配置場所（パス）が深すぎるので、もっと浅い所に置くか、浅い所にここへのシンボリックリンクを作って、そのシンボリックリンクからプロジェクトを利用する。

## ふっ、きさまらではわたしに…グッ…！　こ、このわたしにかたひざをつかせるとはっっ！

いかがでしたか。
「うまく動かないよ！」という方はコメントください。
また、「さいきょうを名乗るなど片腹痛いわ！　お前よりオレの方が強いっ！」的なノウハウをお持ちの方もぜひコメントいただけると嬉しいです。

本記事をこまめにアップデートして、つねにさいきょうのおとこをめざしたいとおもいます。