rspecの自分流書き方

# はじめに

rspecの書き方がいつも迷うのでまとめる。
まだまだ、随時編集を継続していく予定。

## `describe`の書き方
テストケースを説明するような書き方もあるけど、メソッド名だけをシンプルに書くほうが何をテストしてるのかがすぐにわかる。
逆に、何のテストを書いてないのかもすぐにわかる。

参考
https://shinkufencer.hateblo.jp/entry/2018/10/24/233000

#### インスタンスメソッドの場合

```ruby:sample.rb
describe "#method_name" do
end
```

#### クラスメソッドの場合

```ruby:sample.rb
describe ".method_name" do
end
```

## boolearn値をかえすメソッドのマッチャ

厳密なテストにするため、`eq true`か`eq false`を使う。

```ruby:sample.rb
# bad
expect(subject).to be_truthy

# good
expect(subject).to eq true
```


## コントローラー

リクエストスペックで書く。
ポイントは以下の通り。

#### ポイント
- `response.status`を必ず確認する
- 画面に表示された内容や取得した情報が正しく表示されているかテストする場合、`response.body`に期待する内容が含まれているかを確認する

参考
https://qiita.com/t2kojima/items/ad7a8ade9e7a99fb4384

## scopeの場合

```ruby:sample.rb
  describe "test" do
    subject { SbGuaranteeExam.test }

    context "含まれる場合" do
      let!(:test) { build_stubbed :test }

      it "検索される" do
        is_expected.to include test
      end
    end

    context "含まれない場合" do
      let!(:test) { build_stubbed :test }

      it "検索されない" do
        is_expected.not_to include test
      end
    end
  end
```

#### ポイント
- `describe`はスコープ名だけ書く。シャープやコンマは書かなくて良い
- テストケースは、検索されるor検索されないの２ケースのみ設定でOK
- subjectを使う（まだ検討中、、、）

## バリデーションテスト（バリデーションにwith_options onを設定している時のテスト方法）

```ruby:sample.rb
  expect(test_model).to be_invalid(:create)
```

参考
https://qiita.com/hikey/items/a009bfa010b24317e967


## モデルのメソッドの場合

```ruby:sample.rb
  describe ".test_method" do
    context "該当する場合" do
      let(:test) { build_stubbed :test }
      it "有効である" do
        expect(test.test_method).to be_valid
      end
    end
  end
```

#### ポイント
-  `build`を使う
DBにアクセスせず、その属性があればテストができる時は`create`でなくこちらを使う
- `build_stubbed`を使う
`build`は関連されたレコードを生成してしまう。関連するテーブルのレコードがいつようない場合は`build_stubbed`を使う。
ただし、factoryの書き方によっては、効果がない時もある。（(https://zenn.dev/yuji_developer/articles/8be2e10830c797#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B35.-build-%E3%82%84-build_stubbed-%E3%81%A7db%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF%E3%81%97%E3%81%A6%E3%81%84%E3%82%8Bfactory）


```ruby:sample.rb
# 下記のような定義だと、build_stubbed使っても関連データが保存されてしまう
FactoryGirl.define do
  factory :test do
    hoge { create(:huga) }
  end
end

# 下記の書き方なら、build_stubbedを使った時、関連データが保存されない
FactoryGirl.define do
  factory :test do
    association :hoge, factory: :huga
  end
end

```
- subjectを使わない。（まだ検討中、、、）

## デコレーターの場合

```ruby:sample.rb
  describe "#test_method" do
    context "の場合" do
      let!(:test) { build :test }

      it "hogeが表示される" do
        expect(test.test_method).to eq "hoge"
      end
    end

    context "の場合" do
      let!(:test) { build :test }

      it "hugaが表示される" do
        expect(test.test_method).to eq "huga"
      end
    end
  end
```

ポイント
- 可能ならばbuild_stubbedやbildを使う
- subjectを使わない。（まだ検討中、、、）

## モックを使い、メソッドが呼び出されたかテストする場合

##### インスタンスメソッドの場合
```ruby:sample.rb
before {
  test = Test.new
  allow(test).to receive(:test_method)
}

# 呼び出されたかテスト
expect(test).to have_received(:test_method).once
# 呼び出されていないかテスト
expect(test).not_to have_received(:test_method).once

```

##### クラスメソッドの場合

```ruby:sample.rb
before {
  allow(Test).to receive(:test_method)
}

# 呼び出されたかテスト
expect(Test).to have_received(:test_method).once
# 呼び出されていないかテスト
expect(Test).not_to have_received(:test_method)

```

##### モックした時に特定の値を返すようにする
```ruby:sample.rb
before {
  allow(Test).to receive(:test_method).and_return(nil)
}

```

## テストケースごとにテストデータの値を変更したい時

```ruby:sample.rb
  describe "#test_method" do
    let(:test) { build :test, hoge: huga }

    context "hugaがtrueの場合" do
      let!(:huga) { true }

      it "hogeが表示される" do
        expect(test.test_method).to eq "hoge"
      end
    end

    context "hugaがfalseの場合" do
      let!(:huga) { false }

      it "hugaが表示される" do
        expect(test.test_method).to eq "huga"
      end
    end
  end
```