[RSpec] ぼくが既存のプロダクトコードにテストを書く際の慣例


## 概要
表題のシーンにて書き方が自分の中で定型化しているので公開してみるのです。

## 対象となる読者
* これからRSpecを学びたい人
* RSpecでテストをモリモリ書いている人

## 環境
* ruby 2.2.2p95
* RSpec 3.5.4

## 既存modelのテストを書く
### まずプロダクトコードを眺める

``` app/models/user.rb
class User
  include ActiveModel::Model

  attr_accessor :first_name, :last_name

  def fullname_with(delimiter)
    return 'そうじゃない' if ちがう?
    return '雅之じゃない！' if そうじゃない?
    "#{@last_name}#{delimiter}#{@first_name}"
  end

  private

  def ちがう?
  	@first_name == 'ちがう'
  end

  def そうじゃない?
  	@first_name == 'ちがうちがう'
  end
end
```

### describeを列挙する

``` spec/models/user_spec.rb
require 'rails_helper'

describe User, type: :model do
  xdescribe '#fullname_with'
end
```

ちょっと脱線しますが、ここでコメントを **[タスクやストーリーのID] :shirt: describe列挙のみ** などとしてcommitを別けます。privateメソッドのテストも書くかはプロジェクトの方針によりますが、ここでは書かない方針で進めさせてください。

### メソッドの入出力を意識して簡単なテストを書く

``` spec/models/user_spec.rb
require 'rails_helper'

describe User, type: :model do
  describe '#fullname_with' do
    let(:delimiter) {  } # メソッドに渡す入力
    subject { described_class.new.fullname_with(delimiter) } # 何をテストしているのかを明示
    it { is_expected.to be_nil } # 期待する出力
  end
end

```

#### ポイント
* このitは通りませんが **リズムに乗りたいのでここまで一気に書き上げます。** 自分の場合はATOM Editorのプラグイン[ruby-test](https://atom.io/packages/ruby-test)のショートカットキーでテストを即時実行しているのでスピード感が出せています。
* described_classは使わない方が可読性が高いと思うのですが、ちょっと格好付けたい場合に気まぐれで書いてます（格好良いかのツッコミは無しで）。
* 以前は強調したいという意図からsubjectを一行で書ける場合もdo〜endで複数行にしていましたが、コードが縦長になるほうが嫌だなと思うようになり現在は上記のようにしています。
* **itに注釈を書かない**ようにしています。書くとしても処理内容を自然語に翻訳するだけになるので冗長だと思うからです。すると、テストの内容が実行結果から解るようにするため、おのずとitは一行にするのが望ましくなります。
 * ただし複数のitを書くことによりテストの実行時間が著しく低下する場合はこの限りではなく、itに複数行の処理を書いた上で「要は何をチェックしてるの？」を注釈文として記載します。

``` 実行結果
expected: nil
     got: ""
```

ここまで視認して、残念なTYPOなど無いことが解るので「さ〜てモリモリ書くぞぉ」という決意をします。

### 場合分けのテストを追加する
具体的にはcontextを追記します。contextには注釈を記載します。


``` spec/models/user_spec.rb
require 'rails_helper'

describe User, type: :model do
  describe '#fullname_with' do
    let(:user) { described_class.new }
    subject { user.fullname_with(delimiter) }

    context '引数の区切り文字に値がある' do
      let(:delimiter) { '-' }
      it { is_expected.to eq '-' }
      context '姓が`まつやま`、名が `ひでゆき`' do
        before { user.first_name = 'ひでゆき' }
        before { user.last_name = 'まつやま' }
        it { is_expected.to eq 'まつやま-ひでゆき' }
      end
      context '#ちがう?が真' do
        before { expect_any_instance_of(described_class).to receive(:ちがう?) { true } }
        it { is_expected.to eq 'そうじゃない' }
      end
      context '#そうじゃない?が真' do
        before { expect_any_instance_of(described_class).to receive(:そうじゃない?) { true } }
        it { is_expected.to eq '雅之じゃない！' }
      end
    end
    context '引数の区切り文字に値がない' do
      let(:delimiter) {  }
      it { is_expected.to be_blank }
    end
  end
end
```

``` 実行結果
User
  #fullname_with

    引数の区切り文字に値がある
      should eq "-"
      姓が`まつやま`、名が `ひでゆき`
        should eq "まつやま-ひでゆき"
      #ちがう?が真
        should eq "そうじゃない"
      #そうじゃない?が真
        should eq "雅之じゃない！"
    引数の区切り文字に値がない
      should be blank

Finished in 0.01258 seconds (files took 0.23769 seconds to load)
5 examples, 0 failures
```

#### ポイント
* 区切り文字がハイフンかどうかの判断分岐は実装されていないので、そのテストは書きません。
* **区切り文字に値がない場合** も雅之じゃないを書きたい気持ちが湧きますが、やはり分岐が実装されていないのでテストを書きません。
* `#fullname_with` のテストなので `ちがう?` と `そうじゃない?` の処理にはあえて触れていません。必要に応じて別途、それぞれのテストを書きます。

## まとめ
冒頭で書いた、

``` spec/models/user_spec.rb
require 'rails_helper'

describe User, type: :model do
  describe '#fullname_with' do
    let(:delimiter) {  } # メソッドに渡す入力
    subject { described_class.new.fullname_with(delimiter) } # 何をテストしているのかを明示
    it { is_expected.to be_nil } # 期待する出力
  end
end

```

ですが、このテンプレでテストが簡単に書けないメソッドは複雑になっていると思います。本稿では既存のコードにテストを書くというものでしたが、最も言いたかったことは **最初からテストを書くことでメンテナンスコストを抑えれるプロダクトコードを作ろうぜい** ということでした。最初からテストを書いていれば、後の技術的負債を抑えられるコードが書けると思うのです。それこそrubocop先生のABCsizeチェックを無効にするようなメソッドが初めから生まれない、と考えています。

## 関連記事
[[RSpec] テストが書きやすいコードは良いコード](http://qiita.com/choripon/items/7a81c4ff28e0a5abc0af)