フリマアプリの出品テストが上手く書けない人へ

**初投稿です！**
どうか優しい目で見てあげて下さい。お願いします！

さてさて、今回はテストコードの初歩的な事について備忘録的に書き残していこうかと思います。


フリマアプリを開発上で、商品（product）の出品時の

**「必須項目が全て入力してある際は登録できる」**

といったテストコードを書こうと思います！

---
今回登録する中身はこちら↓

###productsテーブル
| カラム名       |       型 |    オプション    |
|:-----------------|------------------:|:------------------:|
| name            |              string |       null: false       |
| price         |            integer |       null: false       |
| description（商品説明）            |              string |        null: false        |
| status（商品の状態）          |              string |       null: false       |
| size         |              string |       null: false       |
| judgment          |              integer |            |
| days（発送までの日にち）        |              string |       null: false       |
| cost（配送料負担者）         |              string |       null: false       |
| prefecture_id         |              integer |       null: false      |
| category_id         |              integer |       null: false, foreign_key: true      |
| brand_id     |            integer |       foreign_key: true      |
| user_id        |              integer |       null: false, foreign_key: true      |

テーブルから
name,
price,
description,
status,
size,
days,
cost,
prefecture_id,
category_id,
user_id
のカラムの値があれば登録できそう( ^ω^ )

というわけで、今回はFactoryBotを用いて、下記の様にテストコードを書きました！！

```ruby:spec/factories/product.rb
FactoryBot.define do

  factory :product do  #値は適当です
    name              {"tomato"}
    price             {111}
    description       {"aaa"}
    status            {"aaa"}
    size              {"aaa"}
    days              {"aaa"}
    cost              {"aaa"}
    prefecture_id     {1}
    category_id       {1}
    user_id           {1}
  end

end
```

```ruby:spec/models/product_spec.rb
require 'rails_helper'
describe Product do
  describe '#create' do
    it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do
      product = FactoryBot.build(:product)
      expect(product).to be_valid
    end
  end
end
```

さてこれで、【bundle exec rspec】っと( ^ω^ )

###　結果

```ruby:ターミナル
Product
  #create
    is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id (FAILED - 1)

Failures:

  1) Product#create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id
     Failure/Error: expect(product).to be_valid
       expected #<Product id: nil, name: "abe", price: 111, description: "aaa", status: "aaa", size: "aaa", judgment: nil, days: "aaa", cost: "aaa", prefecture_id: 1, category_id: 1, brand_id: nil, user_id: 1, created_at: nil, updated_at: nil> to be valid, but got errors: Userを入力してください, Categoryを入力してください
     # ./spec/models/product_spec.rb:7:in `block (3 levels) in <top (required)>'

Finished in 0.18668 seconds (files took 3.15 seconds to load)
1 example, 1 failure
```

失敗( ´ ▽ ` )

エラー分を見てみると、
「UserとCategoryってどこのどいつ誰だよ！そんなのどこにもいねぇぞ！」
と怒られてます。

それもそのはず…
user_idとcategory_idを外部キーで指定しているのにその先が居ないからね…。( ˊ̱˂˃ˋ̱ )

そこで、
FactoryBotにUserとCategoryも追記します！！
まずここでUserとCategoryのテーブルを確認↓

###Usersテーブル
| カラム名       |       型 |    オプション    |
|:-----------------|------------------:|:------------------:|
| nickname           |              string |       null: false       |
| email          |              string |       null: false       |
| encrypted_password         |              string |       null: false       |
| user_image （プロフィール画像）       |              string |           |
| introduction （自己紹介）        |              text |            |
| family_name （姓）       |              string |       null: false       |
| first_name （名）       |              string |       null: false       |
| family_name_kana （セイ）       |              string |       null: false       |
| first_name_kana （メイ）       |              string |       null: false       |
| birth_day （生年月日）      |              date |       null: false       |

###Categoriesテーブル
| カラム名       |       型 |    オプション    |
|:-----------------|------------------:|:------------------:|
| name           |              string |       null: false       |
| ancestry          |              string |            |

なので、FactoryBotに以下の様に追記！

```ruby:spec/factories/product.rb
# ----------追記部分ここから--------------
FactoryBot.define do
  factory :user do  #値は適当です
    nickname          {"sasa"}
    email             {"kkk@gmail.com"}
    password          {"00000000"}  #登録の際に必要なので追記！
    encrypted_password{"00000000"}
    family_name       {"sasaki"}
    first_name        {"goro"}
    family_name_kana  {"sasaki"}
    first_name_kana   {"goro"}
    birth_day         {"1990-08-24"}
  end

  factory :category do  #値は適当です
    name              {"aaa"}
  end
# ----------追記部分ここまで--------------

  factory :product do  #値は適当です
    name              {"tomato"}
    price             {111}
    description       {"aaa"}
    status            {"aaa"}
    size              {"aaa"}
    days              {"aaa"}
    cost              {"aaa"}
    prefecture_id     {1}
    category_id       {1}
    user_id           {1}
  end

end
```

そしてuserとcategoryはこのテスト内で一旦保存されないと、
また「UserとCategoryってどこのどいつ誰だよ！そんなのどこにもいねぇぞ！」
と怒られてしまうので、
buildではなくcreateを使って行きます！！

```ruby:spec/models/product_spec.rb
require 'rails_helper'
describe Product do
  describe '#create' do
    it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do
      user = create(:user)
      category = create(:category)
      product = FactoryBot.build(:product)
      expect(product).to be_valid
    end
  end
end
```

これでいける！！
【bundle exec rspec】っと( ^ω^ )

###　結果

```ruby:ターミナル
Product
  #create
    is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id (FAILED - 1)

Failures:

  1) Product#create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id
     Failure/Error: expect(product).to be_valid
       expected #<Product id: nil, name: "abe", price: 111, description: "aaa", status: "aaa", size: "aaa", judgment: nil, days: "aaa", cost: "aaa", prefecture_id: 1, category_id: 1, brand_id: nil, user_id: 1, created_at: nil, updated_at: nil> to be valid, but got errors: Userを入力してください, Categoryを入力してください
     # ./spec/models/product_spec.rb:8:in `block (3 levels) in <top (required)>'

Finished in 0.17322 seconds (files took 2.77 seconds to load)
1 example, 1 failure
```

…えっ？_:(´ཀ`」 ∠):

同じエラーでとる…何故…？？

もしかして、userもcategoryもcreateできてない？
と思い、【binding.pry】を【category = create(:category)】の直下に記入し、
確かめてみると、、、

```ruby:
Product
  #create

From: /Users/hoge/Desktop/GitHub/hogehoge/spec/models/product_spec.rb @ line 7 :

     2: describe Product do
     3:   describe '#create' do
     4:     it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do
     5:       user = create(:user)
     6:       category = create(:category)
 =>  7:       binding.pry
     8:       product = build(:product)
     9:       expect(product).to be_valid
    10:     end
    11: 
    12:     # it "is invalid without a name" do

[1] pry(#<RSpec::ExampleGroups::Product::Create>)> user
=> #<User id: 15, nickname: "sato", email: "kkk@gmail.com", user_image: nil, introduction: nil, family_name: "sato", first_name: "kenta", family_name_kana: "sato", first_name_kana: "kenta", birth_day: "1990-08-24", created_at: "2020-03-21 05:17:39", updated_at: "2020-03-21 05:17:39">
[2] pry(#<RSpec::ExampleGroups::Product::Create>)> category
=> #<Category:0x00007fe4caab5138 id: 7, name: "aaa", ancestry: nil, created_at: Sat, 21 Mar 2020 05:17:39 UTC +00:00, updated_at: Sat, 21 Mar 2020 05:17:39 UTC +00:00>
[3] pry(#<RSpec::ExampleGroups::Product::Create>)> 

```

なんてことない、userとcategoryのidが違っていただけでした。( ´ ▽ ` )
そりゃ常にidが１な訳ないよね。。。

と言うことでさらにテストコードを下記の様に修正！！

```ruby:spec/models/product_spec.rb
require 'rails_helper'
describe Product do
  describe '#create' do
    it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do
      user = create(:user)
      category = create(:category)
　　　 #修正点！！　user_id: user[:id], category_id: category[:id]を追記、これでテスト時に保存されたuserとcategoryのidが呼び出され、上書きされる
      product = FactoryBot.build(:product, user_id: user[:id], category_id: category[:id])
      expect(product).to be_valid
    end
  end
end
```

これでどうかな？
( ^ω^ )つ【bundle exec rspec】

###　結果

```ruby:ターミナル
Product
  #create
    is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id

Finished in 0.07648 seconds (files took 2.63 seconds to load)
1 example, 0 failures
```

無事テスト成功！！

やったぜ！✌︎('ω'✌︎ )( ✌︎'ω')✌︎


## まとめ

テスト内容は単純でも、
**アプリごとにテーブルなどの制約（NotNullや、外部キーなど）も異なる**ので、
そこに気をつけてテストコードを書いていかないと、
私の様に、テストコードの沼にハマる事になります。

この記事が少しでも初学者の役に立ちます様に。

ここまで読んでくれて
ありがとう。
また次の記事でお会いしましょう！！♪( ´θ｀)ノそれでは