테스트하는 동안 일부 경우에만 실행하고 싶은 애프터 생성 콜백으로 모델을 테스트하고 있습니다. 공장에서 콜백을 건너 뛰거나 실행하려면 어떻게해야합니까?
class User < ActiveRecord::Base
after_create :run_something
...
end
공장:
FactoryGirl.define do
factory :user do
first_name "Luiz"
last_name "Branco"
...
# skip callback
factory :with_run_something do
# run callback
end
end
답변
이것이 최선의 해결책인지 확실하지 않지만 다음을 사용하여 성공적으로 달성했습니다.
FactoryGirl.define do
factory :user do
first_name "Luiz"
last_name "Branco"
#...
after(:build) { |user| user.class.skip_callback(:create, :after, :run_something) }
factory :user_with_run_something do
after(:create) { |user| user.send(:run_something) }
end
end
end
콜백없이 실행 :
FactoryGirl.create(:user)
콜백으로 실행 :
FactoryGirl.create(:user_with_run_something)
답변
콜백을 실행하지 않으려면 다음을 수행하십시오.
User.skip_callback(:create, :after, :run_something)
Factory.create(:user)
skip_callback은 실행 후 다른 사양에서 지속되므로 다음과 같은 사항을 고려하십시오.
before do
User.skip_callback(:create, :after, :run_something)
end
after do
User.set_callback(:create, :after, :run_something)
end
답변
이러한 솔루션 중 어느 것도 좋지 않습니다. 클래스가 아닌 인스턴스에서 제거해야하는 기능을 제거하여 클래스를 손상시킵니다.
factory :user do
before(:create){|user| user.define_singleton_method(:send_welcome_email){}}
콜백을 억제하는 대신 콜백의 기능을 억제합니다. 어떤면에서는이 접근 방식이 더 명시 적이기 때문에 더 좋습니다.
답변
다른 사용자를 만들 때 after_save 콜백을 더 재사용 할 수 있도록 @luizbranco의 답변을 개선하고 싶습니다.
FactoryGirl.define do
factory :user do
first_name "Luiz"
last_name "Branco"
#...
after(:build) { |user|
user.class.skip_callback(:create,
:after,
:run_something1,
:run_something2)
}
trait :with_after_save_callback do
after(:build) { |user|
user.class.set_callback(:create,
:after,
:run_something1,
:run_something2)
}
end
end
end
after_save 콜백없이 실행 :
FactoryGirl.create(:user)
after_save 콜백으로 실행 :
FactoryGirl.create(:user, :with_after_save_callback)
내 테스트에서는 사용 된 메서드가 테스트 예제에서 일반적으로 원하지 않는 추가 항목을 실행하기 때문에 기본적으로 콜백없이 사용자를 생성하는 것을 선호합니다.
———- UPDATE ———— 테스트 스위트에 불일치 문제가 있었기 때문에 skip_callback 사용을 중단했습니다.
대체 솔루션 1 (스텁 및 스텁 해제 사용) :
after(:build) { |user|
user.class.any_instance.stub(:run_something1)
user.class.any_instance.stub(:run_something2)
}
trait :with_after_save_callback do
after(:build) { |user|
user.class.any_instance.unstub(:run_something1)
user.class.any_instance.unstub(:run_something2)
}
end
대체 솔루션 2 (내가 선호하는 접근 방식) :
after(:build) { |user|
class << user
def run_something1; true; end
def run_something2; true; end
end
}
trait :with_after_save_callback do
after(:build) { |user|
class << user
def run_something1; super; end
def run_something2; super; end
end
}
end
답변
Rails 5- skip_callback
FactoryBot 팩토리에서 건너 뛸 때 인수 오류가 발생합니다.
ArgumentError: After commit callback :whatever_callback has not been defined
rails 5 에서 skip_callback이 인식되지 않는 콜백을 처리하는 방법 이 변경되었습니다 .
ActiveSupport :: Callbacks # skip_callback은 이제 인식 할 수없는 콜백이 제거되면 ArgumentError를 발생시킵니다.
언제 skip_callback
공장에서 호출되면, AR 모델의 실제 콜백이 아직 정의되지 않았습니다.
모든 것을 시도하고 나처럼 머리카락을 뽑았다면 여기에 해결책이 있습니다 (FactoryBot 문제 검색에서 얻었습니다) ( 부품 참고raise: false
).
after(:build) { YourSweetModel.skip_callback(:commit, :after, :whatever_callback, raise: false) }
원하는 다른 전략과 함께 자유롭게 사용하십시오.
답변
이 솔루션은 저에게 효과적이며 Factory 정의에 추가 블록을 추가 할 필요가 없습니다.
user = FactoryGirl.build(:user)
user.send(:create_without_callbacks) # Skip callback
user = FactoryGirl.create(:user) # Execute callbacks
답변
Rspec 3에서 간단한 스텁이 가장 잘 작동했습니다.
allow(User).to receive_messages(:run_something => nil)