Redmineのpluginを開発した際にrspecを使って自動テストがしたい

結構苦戦したので、次回は苦戦しないようにここにメモしておく なお、各バージョンなどは以下

- OS(Windows7)
- ruby (2.0.0p648)
- rails (4.2.7.1)
- rspec-rails (3.5.2)
- poltergeist (1.12.0)
- database_cleaner (1.5.3)
- capybara (2.11.0)
- launchy (2.4.3)

## 環境構築

参考にしたサイト様達<br>
<http://ylgbk.hatenablog.com/entry/2015/02/16/120000><br>
[Redmine pluginの開発について当初自分が疑問に思ってたことに回答](http://qiita.com/t_oginogin/items/fcefd6a8ed5b34e62d0f) ほか<br>
※ほかは後ほど本文中に記載

### フォルダ構成

プラグイン名/spec/spec_helper.rbとかもなかったので作成

> redmine/
> ├(略)
> ├plugins
> │ ├(プラグイン名)
> │ ├(略)
> │ ├spec/
> │ │ ├factories/
> │ │ ├models/
> │ │ ├views/
> │ │ └spec_helper.rb
> │ └ (略)
> ├spec
> │ └spec_helper.rb
> └(略)

### 各種ファイルの内容

```ruby:gemfile
group :development, :test do
    gem 'pry-rails'  
    gem 'pry-doc'    
    gem 'pry-byebug'
    gem 'pry-stack_explorer'
    gem 'rspec-rails'
    gem 'factory_girl_rails'
end

group :test do
    gem 'minitest'
    gem 'rails-dom-testing'
    gem 'mocha'
    gem 'simplecov'
    gem 'capybara'
    gem 'poltergeist'
    gem 'selenium-webdriver'
    gem 'database_cleaner'
    gem 'faker'
    gem 'database_cleaner'
    gem 'launchy'
    gem 'timecop'
end
```

↑TODO:そもそも、試行錯誤した後なので使っていないのも結構ありそう

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

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

ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.use_transactional_fixtures = true
    config.infer_base_class_for_anonymous_controllers = false
    config.order = 'random'
    RSpec.configure do |config|
        config.include FactoryGirl::Syntax::Methods
    end
end
```

↑ここはほぼ手を入れてないはず？

```ruby:redmine/plugins/(プラグイン名)/spec/spec_helper.rb
require File.expand_path(File.dirname(__FILE__) + '/../../../spec/spec_helper')
require File.expand_path('../../../../config/environment', __FILE__)
require 'rspec/rails'
require 'capybara'
require 'capybara/rspec'
require 'capybara/poltergeist'
require 'selenium-webdriver'

Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver

RSpec.configure do |config|
    config.use_transactional_fixtures = false
    config.infer_spec_type_from_file_location!
    config.include FactoryGirl::Syntax::Methods
    FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
    FactoryGirl.find_definitions
    config.before(:all) do
        FactoryGirl.reload
    end

    config.before(:each) do
      DatabaseCleaner.strategy = :truncation
    end

    config.before(:each) do
      DatabaseCleaner.start
    end

    config.after(:each) do
      DatabaseCleaner.clean
    end
end
Capybara.register_driver :poltergeist do |app|
    Capybara::Poltergeist::Driver.new(app, inspector: true)
end
```

↑TODO:ここも明らかに使ってない設定とか残っていそうなので後で整理する

### 実行

後は普段と同じように(プラグイン名)/spec/models/hogehoge_spec.rbなどを作成して実行する。<br>
ちな実行コマンドは下記<br>
`bundle exec rspec ./pulgins/(プラグイン名)/spec/models/hogehoge_spec.rb`<br>
※一括実行する場合はmodels~は省略

## 躓いた問題達
1.
問題：jsのテストができない（js: trueオプションをつけると動作がおかしくなる）
原因：DriverがそもそもJSに対応してなかった
参考：[Capybaraを使う際に知っておきたいこと
](http://qiita.com/take/items/779747e0981355e569ad)

2.
問題：SQLite3::BusyExceptionがおきる
原因：database_cleanerで以下設定を行っていたから？（なぜか要調査）
`DatabaseCleaner.strategy = :transaction`
transaction→truncationにすると動作は遅いがなぜか動く
と思ったらそれらしい記事があった↓
参考：<http://stackoverflow.com/questions/29387097/capybara-and-chrome-driver-sqlite3busyexception-database-is-locked>

3.
問題：spec実行時にpoltergeistのドライバーがないって言われる
原因：spec_helperにrequireを書いてなかった
phantomjsを環境変数のパスに追加していなかった
参考：[初心者大歓迎！RSpec 3でドラッグアンドドロップ機能をテストする方法(スクリーンキャスト付き)](http://qiita.com/jnchito/items/bdd80c1085fa082e7d7a)

## その他

### viewのテストでログインしたい

Redmineではユーザーのパスワードは暗号化されているため、テスト時に強引に上書きしてやった。

```test_view_spec.rb
let!(:user) { FactoryGirl.create(:test_admin) }
before do
    visit home_path
    find('.login').click
    @user = User.find_by_login(user.login)
    User.find_by_login(user.login).update_attribute(:password, 'password')
    User.find_by_login(user.login).update_attribute(:must_change_passwd, false)
    fill_in 'password', with: 'password'
    fill_in 'username', with: @user.login
    find('[name=login]').click
end
```

### 一応国際化はしたけど、要件が日本語のみなので日本語固定でテストする

デフォルトの言語はSettingに保存されているみたいなので、対象のレコードを作成。<br>
`Setting.create(name: 'default_language', value: 'ja')`

...普通にI18n使えばいいじゃん...<br>
ちな参考↓ <br>
<http://easyramble.com/rspec-tests-with-i18n.html>

### Viewのテスト中でどんな画面が開かれているのかを確認したい（度忘れしてた）

save_and_open_pageを使いましょう

## ふりかえり
ツッコミどころが多そうなのはご愛嬌...