1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ショッピングサイトアプリの購入機能テスト(model)をRSpecとFactorybotで構築してみた。

Last updated at Posted at 2020-03-25

はじめに

ショッピングサイトアプリ(疑似フリマアプリ)を作成していて、購入機能を担当することになりました。
「RSpecでmodelのテストコードを作成せよ」とのお達しがありましたので、取り組んでみました。

その結果、associationで「belongs_to」の関係にあるモデルの連携に
ハマりましたので、備忘録もかねて投稿します。

前提

ここでは支払処理が完了した後に購入記録を登録する機能のテストを説明しています。
支払機能(payjplなどのAPI)について触れませんのでご了承ください。

参考記事

【FactoryBot】associationの使い方

開発環境

ruby 2.5.1
rails 5.2.4.1
RSpec 3.9.0
factory_bot 5.1.1
devise 4.7.1

ER図

ショッピングサイトアプリのテーブル構成を次のように定義し、
rails db:migrateコマンドじ実行とmodelの構築が済んだものとします。

スクリーンショット 2020-03-25 22.19.32.png

一見するとわかりにくいかもしれませんが、
このような考え方になります。

  1. 出品者

    • ユーザーを登録する。(user)
    • 発送元住所を登録する。(address)
    • 売りたいモノを出品する。 (item)
  2. 購入者

    • ユーザーを登録する。(user)
    • 発送先住所を登録する。(address)
    • 出品されたモノを購入する。 (trade)

ここで注意しなければならないことは

  • userとaddressは出品者と購入者それぞれに必要であること。
  • itemは出品者のみでがuserとaddressに従属すること。
  • tredeは出品者のitemと、購入者のuserとaddressが必要であること。

となります。

他の開発者が作成したfactoryデータコードを流用しようとしましたが、出品者と購入者の2種類を同時に
テストするように想定されていないため、使い回しができませんでした(横着をしてはいけない)。

よって、購入機能専用に出品者と購入者のコードを書くことにしました。

Factorybotでテストデータを作ろう

まずはusers

spec/factories/users.rb
FactoryBot.define do
  # 出品者用データ factory名は「seller」とします。
  # 「sequence」はspec.rbから呼び出されるたびにカウントアップしてくれる機能です。
  factory :seller, class: User do
    sequence(:nickname)        { |i| "出品者_#{i}"}
    sequence(:email)           { |i| "seller_#{i}@test.com"}
    password                   {"00000000b"}
    last_name                  {"苗字"}
    first_name                 {"名前"}
    last_name_kana             {"ミョウジカナ"}
    first_name_kana            {"ナマエカナ"}
    birthday                   {"20190101"}
    telephone_number           {"1234567890"}
  end

  # 購入者用データ factory名は「buyer」とします。
  factory :buyer, class: User do
    sequence(:nickname)        { |i| "購入者_#{i}"}
    sequence(:email)           { |i| "byuer_#{i}@test.com"}
    password                   {"00000000c"}
    last_name                  {"苗字"}
    first_name                 {"名前"}
    last_name_kana             {"ミョウジ"}
    first_name_kana            {"ナマエ"}
    birthday                   {"20190101"}
    telephone_number           {"1234567890"}
  end
end

続いてareas

spec/factories/areas.rb
FactoryBot.define do
  # 出品者地域 
  factory :seller_area, class: Area do
    name {"北海道"}
  end

  # 購入者地域 
  factory :buyer_area, class: Area do
    name {"東京都"}
  end
end

さらにaddresses

spec/factories/addrsses.rb
FactoryBot.define do
  # 出品者住所
  factory :seller_address, class: Address do
       
    zip_code         {"1234567"}
    city             {"city_1"}
    number           {"number_1"}
    building         {"building_1"}
    last_name        {"出品"}
    first_name       {"太郎"}
    telephone_number {"03-1234-5678"}

    #出品者のareaとuserを連携します。
    association :area, factory: :seller_area
    association :user, factory: :seller

  end

  # 購入者住所
  factory :buyer_address, class: Address do

    zip_code         {"3214567"}
    city             {"city_2"}
    number           {"number_2"}
    building         {"building_2"}
    last_name        {"購入"}
    first_name       {"次郎"}
    last_name_kana   {"ジロウ"}
    first_name_kana  {"コウニュウ"}
    telephone_number {"03-1234-5678"}

    #購入者のareaとuserを連携します。
    association :area, factory: :buyer_area
    association :user, factory: :buyer

  end
end

やっとitems

spec/factories/items.rb
FactoryBot.define do

  # 出品者用データ
  factory :seller_item, class: Item do

    sequence(:title) { |i| "product_#{i}"}
    sequence(:description) { |i| "description_#{i}"}

    price            {1000.000}

    #出品者のaddressと連携します。
    association :address, factory: :selladdress
    #出品者のaddress内にあるuserと連携します。
    user             {address.user}

  end
end

最後にtrades

spec/factories/trades.rb
FactoryBot.define do
  #購入用データ
  factory :trade do
    status_num  {0}

    #出品者のitemと連携します。
    association :item, factory: :seller_item

    #購入者のaddressと連携します。
    association :address, factory: :buyer_address
    #購入者のaddress内にあるuserと連携します。
    user        {address.user}
  end

end

RSpecでテストコードを作ろう

tradeのテストコードはたったこれだけ

spec/models/trade_spec.rb
require 'rails_helper'

RSpec.describe Trade, type: :model do
  describe "#create" do
    #factoryデータを呼び出すときに、associationで関連付けした場合は、createを使います。
    #buildを使うとテストそのものが失敗します。
    let(:trade)    { create(:trade) }
    it "is valid trade" do
      #ここでtradeを呼び出すことで、「let(:trade)」が実行されます。
      expect(trade).to be_valid
    end
  end
end

ターミナルでテストを実行すると

こうなりました。

terminal
% bundle exec rspec spec/models/trade_spec.rb

Trade
  #create
    is valid trade

Finished in 1.12 seconds (files took 5.19 seconds to load)
1 examples, 0 failures
% 

「is valid trade」と表示されたので、
登録テストが正常終了したことがわかりました。

まとめ

  • 購入機能テスト用のfactoryデータは、出品者と購入者それぞれに必要な範囲で作成しなければならないこと。
  • 他の開発者が作成したfactoryコードは流用しない方が良いこと。(そもそも購入機能を想定して作られたモノではないことがほとんど)

となりました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?