Rspecの文法の基礎


```ruby:spec/order_spec.rb
describe Order do
  before do
    order.add_entry(LineItem.new(:item => Item.new(
      :price => Money.new(1.11, :USD)
    )))
  end

  let(order) { Order.new }

  it "sums the prices of its line items" do
    order.add_entry(LineItem.new(:item => Item.new(
      :price => Money.new(2.22, :USD),
      :quantity => 2
    )))
    expect(order.total).to eq(Money.new(5.55, :USD))
  end
end
```

[Rspec](https://github.com/rspec/rspec)は[rspec-core](https://github.com/rspec/rspec-core), [rspec-expectations](https://github.com/rspec/rspec-expectations), [rspec-mocks](https://github.com/rspec/rspec-mocks)の3つにわかれており、それぞれRspecの基本文型、多様な比較演算、モックオブジェクトを定義している。このドキュメントは、文法に焦点を当てるため、[rspec-core](https://github.com/rspec/rspec-core)の中の基礎的な部分と、Rails用に[rspec-rails](https://github.com/rspec/rspec-rails), [capybara](https://github.com/jnicklas/capybara)が拡張する文法について触れる。
テストの中身の書き方については、http://qiita.com/awakia/items/d880250adc8cdbe7a32f を参照

## 基本文型

https://github.com/rspec/rspec-core
https://www.relishapp.com/rspec/rspec-core/v/3-0/docs/example-groups/basic-structure-describe-it

```ruby:spec/models/class_spec.rb
describe <クラス名> do
  it "<期待する動作の内容>"
    # ...
  end

  context "<条件の内容>" do
    it "<contextの条件下で期待する動作の内容>" do
      # ...
    end
  end
end
```

ここで、

- `context`は、`describe`に置き換え可能
- `it`は、`specify`または`example`に置き換え可能

なので、文脈に合わせて使いやすい用語を使えば良い。

なお、デフォルトの設定では、名前として`<クラス名>_spec.rb`というようにサフィックスとして`_spec.rb`がないと`rspec`コマンドで全体を走らせた時に無視されるようになるので気をつけること。

### 何をしているか

- `describe`,`context`は[ExampleGroup](http://rubydoc.info/gems/rspec-core/RSpec/Core/ExampleGroup)を生成
- `it`,`specify`,`example`は[Example](http://rubydoc.info/gems/rspec-core/RSpec/Core/Example)を生成

なお、topレベルの`describe`はExampleGroupを生成するが、役割はそれだけではない。

## Railsを使っている場合

[rspec-rails](https://github.com/rspec/rspec-rails)というのを使う。

これは、`expect ... to`の後に使える

- be_a_new
- render_template
- redirect_to
- route_to
- be_routable

などのRails用のMatcherを提供する他、

- Model
- Controller
- View
- Request
- Feature
- Mailer
- Routing
- Helper

など、それぞれのタイプの特徴に合わせたスペックの書き方を提供する。

例えばモデルタイプのテストだと`spec/models`の下におくか
`describe ... type: :model`としてテストを書く。

それぞれのタイプにより何がロードされるかや、使えるメソッドなどが異なり、ここに書ききれないので、それぞれのテストを書く際にドキュメントを参照すると良い。

ドキュメントは以下だが、概要はgithubの方がわかりやすいので詳しく知りたくなった時のみこちらを参照すると良い。
https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/directory-structure


### Capybaraを使っている場合

rspec-railsのfeatureテストはほぼ[capybara](https://github.com/jnicklas/capybara)の使用を前提としている。

Capybaraはユーザーがブラウズする課程をテストでそのまま書くようなFeatureテストを作成するときに便利なgem
https://github.com/jnicklas/capybara#using-capybara-with-rspec


これを使っている場合、

- `describe ... type: :feature`の代わりに`feature`
- `before`の代わりに、`background`
- `it`の代わりに、`scenario`
- `let`の代わりに`given`

が使えるようになり、より自然な英語で以下のように書けるようになる。


```ruby:spec/features/signing_in_spec.rb
feature "Signing in" do
  background do
    User.make(:email => 'user@example.com', :password => 'caplin')
  end

  given(:other_user) { User.make(:email => 'other@example.com', :password => 'rous') }

  scenario "Signing in as another user" do
    visit '/sessions/new'
    within("#session") do
      fill_in 'Login', :with => other_user.email
      fill_in 'Password', :with => other_user.password
    end
    click_link 'Sign in'
    expect(page).to have_content 'Invalid email or password'
  end
end
```