Rails 基礎 Part 04 -- index の単体テストを RSpec と FactoryBot で作る
Tags: ruby, rails, factorybot, rspec
Published: 2023-05-21 23:06:01


## why

コーチングを受けて、テストピラミッドを学んだ。
これにより、単体テストを絶対に書くべきだと考えた。

単体テストを全て書くためには、スピードを上げる必要があると考えた。
テストを作るスピードが遅ければ、テストだけどんどん別チケットになってたまってしまうからだ。

テストを作るスピードを上げるために、プライベートで一から作ってみることにした。

---

## テストピラミッドについて

テストピラミッドは、下記の図のようになっている。

```
               /\
              /  \
             / UI \
            / テスト \
           /---------\
          / 統合テスト  \
         /-------------\
        / ユニットテスト   \
       /------------------\

```

参考は下記 URL

https://thinkit.co.jp/article/13346

---

## 今回の作業に必要なもの

1. Controller の実装本体。index メソッド。前回の記事で作成ずみ
2. Rspec ライブラリ。Rails にビルドインされている。
2. FactoryBot のライブラリ。
3. FactoryBot でのテストデータ生成用のファクトリー定義ファイル
4. RSpec と ファクトリー定義ファイル を使った単体テストのファイル

---

## ファクトリーとは？

データを生成する場所のこと。

現実世界の具体例で考えてみよう。

僕らはコンビニで食べ物を買う。
しかしコンビニでは基本的に物を製造しない。
製品は別の場所、工場でで作られる。
それからコンビニに運ばれて売られる。

これをデータに置き換えよう。
データを生成する「工場」がまさに「ファクトリー」。
そして今回、このファクトリーを単体テストフレームワークである RSpec で使用する。


---
---

# 前回作った API の GET から UT を作っていく

---

## Gemfile でライブラリのインストール

単体テスト専用のデータを作るため、`FactoryBot` というライブラリをインストールする。

```ruby
Gemfile
```

```ruby
group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri mingw x64_mingw ]
  gem 'rspec-rails', '~> 6.0.0'
  gem 'factory_bot_rails'

end
```

これで development or test でのみ動く

FactoryBot の README は下記。

https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#update-your-gemfile

bundle install でプロジェクトに入る

---

## データ挿入の factries

```ruby
spec/factories/bank_tranksactions.rb
```

これを作成

```ruby
FactoryBot.define do
  factory :bank_transaction do
    account_number { '1234567' }
    amount  { 250_000 }
    description  { "おちんぎん" }
#     sequence(:username) { |n| "user#{n}" }
  end
end
```

呼ばれるとデータが入る factories を作る

---

## Controller のテスト本体

```ruby
spec/controllers/bank_transactions_controller_spec.rb
```

```ruby
describe BankTransactionsController do
  context 'when logged in' do
      before do
        FactoryBot.create(:bank_transaction)
      end
      it 'get all bank transactions' do
        # FactoryBot.build(:bank_transaction)
        # FactoryBot.create(:bank_transaction)
        get :index

        # pp response.body
        amount = JSON.parse(response.body).first['amount'].to_i
        expect(amount).to eq 250000
      end

      after do
        BankTransaction.destroy_all
      end
  end
end
```

1. describe ControllerName でコントローラー指定
2. before FactoryBot.create でテスト実行前にデータを作成して DB に入れる。
  * build では DB には入らない。
3. get :methodName でメソッドを指定
4. json が返ってくるのでパースしてキーを指定
5. expect(key).to eq value で比較
6. after でデータを破棄

このサイクル。


---

## 実際の実行

```
Terminal
```

エラーがある場合

```ruby
rspec spec/controllers/bank_transactions_controller_spec.rb
F

Failures:

  1) BankTransactionsController when logged in get all bank transactions
     Failure/Error: json = JSON.parse(response.body).first.to_i
     
     NoMethodError:
       undefined method `to_i' for {"id"=>1, "account_number"=>"1234567", "amount"=>"250000.0", "description"=>"おちんぎん", "created_at"=>"2023-05-21T05:23:39.241Z", "updated_at"=>"2023-05-21T05:23:39.241Z"}:Hash
     # ./spec/controllers/bank_transactions_controller_spec.rb:12:in `block (3 levels) in <main>'
```

ない場合

```ruby
kaede0902@V bank_transactions_api % rspec spec/controllers/bank_transactions_controller_spec.rb
.

Finished in 0.08155 seconds (files took 1.77 seconds to load)
1 example, 0 failure
```