RailsApp Rails FactoryBot RSpec 2018年 11月 21日
昨日の shared_example を使った Teacher モデルのテストを作成する.
mkdir -p spec/models
require 'rails_helper'
# Teacher model の仕様を開始
RSpec.describe Teacher, type: :model do
# validation の共通テスト (使わないものはコメントしてある)
context 'common validation check' do
# テスト対象を指定する.今回は :hkob というキーで指定された FactoryBot である
subject { teacher_factory :hkob }
# ここから下に出てくる it_behaves_like は shared_examples.rb に記載した共有テストである.
# 最初の引数が共有テストの名前,その後ろがそのテストに渡す引数である.
# name と email 属性が nil の場合に validate に失敗することを確認(presence validation)
# FactoryBot の作成確認のため,全ての属性が正しい場合に有効であることも確認している
it_behaves_like :presence_validates, %i[name email]
# email が重複している場合に validate に失敗することを確認 (unique validation)
it_behaves_like :unique_validates, %i[email], -> { teacher_factory :taro }
#it_behaves_like :plural_unique_validates, %i[], -> { teacher_factory :other }
# モデルオブジェクトが削除できるかを確認 (destroy validation)
it_behaves_like :destroy_validates
#it_behaves_like :reject_destroy_validates
#it_behaves_like :belongs_to, :teacher, has_many: %i[], has_one: %i[], children: :optional, child: :optional
#it_behaves_like :dependent_destroy, :teacher, %i[has_many has_one]
#it_behaves_like :reject_destroy_for_relations, :teacher, %i[has_many has_one]
#it_behaves_like :destroy_nullify_for_relations, :teacher, %i[has_many has_one]
end
# 複数の FactoryBot を生成した後に実行できるメソッドの仕様
context 'after some teachers are registrered' do
# 準備する FactoryBot の key を配列で指定しておく
model_keys = %i[hkob taro]
# 上記で作成した key 配列に対応した FactoryBot を targets として事前準備する.
# let! なので,it の前に必ず準備された状態になる(遅延実行ではない).
let!(:targets) { teacher_factories model_keys }
# クラスメソッドに対する仕様 (今回はなし)
describe 'Teacher class' do
# テスト対象を Teacher クラスとする.
subject { Teacher }
# 今回はテストはない
#it_behaves_like :mst_block, -> t do
# {
# method1: [v1, a1, v2, a2, ...],
# method2: [v1, a1, v2, a2, ...],
#end
#
#it_behaves_like :msta_block, -> t do
# {
# method1: [v1, a1, v2, a2, ...],
# method2: [v1, a1, v2, a2, ...],
# }
#end
#
#it_behaves_like :mst, :METHOD1, -> { [v1, teacher_factories(model_keys.values_at()), v2, teacher_factories(model_keys.values_at())] }
#it_behaves_like :msta, :METHOD1, -> { [v1, teacher_factories(model_keys.values_at()), v2, teacher_factories(model_keys.values_at())] }
end
# クラスインスタンスに対する仕様
context 'Teacher instances' do
# 上記で作成した複数の FactoryBot をテスト対象とする.
subject { targets }
# amst は array method send test の略で配列の個々の要素に method を呼び出します.
# ハッシュの中身は,キーが method 名, 値の配列が引数とその結果を並べたものです.
# 引数がない場合には,引数の部分は nil とします.
# 最初のテストでは targets のそれぞれに対して,name を渡した時に,その属性値である name の値が返ってくることを期待します.
# ただし,この example 内で it は内部に一つだけしか存在しないため,block の最初だけしか targets が作られない.
# インスタンスの値を変えるような副作用があるメソッドを読んだ場合には,後続のメソッドは副作用の影響を受けることに注意が必要である.
# 逆に各メソッドのテストの度にインスタンスが作られないので,ベタに it を並べるよりもテストは高速化される.
it_behaves_like :amst_block, -> t do
{
name: [nil, %w[小林弘幸 高専太郎]],
email: [nil, %w[hkob@example.com taro@example.com]],
}
end
#it_behaves_like :amsta_block, -> t do
# {
# method1: [v1, a1, v2, a2, ...],
# method2: [v1, a1, v2, a2, ...],
# }
#end
#
#it_behaves_like :amst, :METHOD1, -> { [v1, a1, v2, a2] }
#it_behaves_like :amsta, :METHOD1, -> { [v1, a1, v2, a2] }
end
end
end
16:00:22 - INFO - Running: spec/models/teacher_spec.rb
Running via Spring preloader in process 50685
Teacher
common validation check
behaves like presence_validates
should be valid
when name is nil
should not be valid (FAILED - 1)
when email is nil
should not be valid
behaves like unique_validates
when another object has same email
should not be valid
behaves like destroy_validates
should destroy
should change `Teacher.count` by -1
after some teachers are registrered
Teacher instances
behaves like amst_block
amst: name
amst: email
should receive above methods(amst)
Failures:
1) Teacher common validation check behaves like presence_validates when name is nil should not be valid
Failure/Error: is_expected.to_not be_valid
expected #<Teacher id: 114, name: nil, email: "hkob@example.com", created_at: "2018-11-14 07:00:24", updated_at: "2018-11-14 07:00:24"> not to be valid
Shared Example Group: :presence_validates called from ./spec/models/teacher_spec.rb:8
# ./spec/support/shared_examples.rb:10:in `block (4 levels) in <main>'
# -e:1:in `<main>'
Finished in 0.26226 seconds (files took 0.8522 seconds to load)
6 examples, 1 failure
Failed examples:
class Teacher < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :name, presence: {message: 'は空にはできません.'}
end
長くなったので今日はここまで