2017-01-11 10 views
2

모델의 before_update 콜백을 테스트하려고합니다.Rspec 및 FactoryGirl을 사용하여 레일스 모델에서 before_update 콜백을 테스트하는 방법은 무엇입니까?

모델/option.rb :

class Option < ApplicationRecord 
    belongs_to :activity 

    has_many :suboptions, class_name: "Option", foreign_key: "option_id" 

    belongs_to :parent, class_name: "Option", optional: true, foreign_key: "option_id" 

    accepts_nested_attributes_for :suboptions, allow_destroy: true, 
    reject_if: ->(attrs) { attrs['name'].blank? } 

    validates :name, presence: true 

    before_create :set_defaults 
    before_update :set_updates 


    def set_defaults 
    self.suboptions.each do |sbp| 
     sbp.activity_id = self.activity_id 
    end 
    end 

    def set_updates 
    suboptions.each do |child| 
     child.activity_id = self.activity_id 
    end 
    end 
end 

사양/모델/option.rb :

require 'rails_helper' 

RSpec.describe Option, type: :model do 

    describe "Callbacks" do 
    it "before_create" do 
     suboption = create(:option) 
     option = create(:option, suboptions:[suboption]) 
     option.run_callbacks(:create) {false} 
     expect(option.suboptions.first.activity_id).to eq suboption.activity_id 
    end 

    it "before_update" do 

    end 
    end 



end 

내가 성공적으로 before_create 콜백을 테스트 (적어도 그것이 나에게 올바른 결과를 주었다). 하지만 before_update 콜백을 테스트하는 방법을 모르겠습니다. 그것을 할 수있는 방법이 있습니까?

답변

1

run_callbacks을 사용하는 해결책이 있습니다. 나는 옵션과 하위 옵션을 만들었습니다.그럼 난 옵션의 activity_id를 업데이트하고 (나는 {true}를 사용하는 경우, 그것은 before_updateafter_update 콜백을 실행하는 것) before_update 콜백을 실행하는 option.run_callbacks(:update) {false}을 사용 :

it "before_update" do 
    suboption = create(:option) 
    option = create(:option, suboptions:[suboption]) 
    option.update(activity_id: 5) 
    option.run_callbacks(:update) {false} 
    expect(option.suboptions.first.activity_id).to eq option.activity_id 
end 

을 나는 option.run_callbacks(:update) {false}를 사용하지 않을 경우,식이를 얻을 것으로 예상 옵션 및 하위 옵션에 대해 다른 activity_id. 그런 코드를 사용하면 테스트가 올바르게 실행되고 옵션과 하위 옵션의 activity_id가 동일합니다.

2

확인. 나는 처음부터 시작하려고 노력할 것입니다.

콜백을 테스트하려면 필요할 때 호출되는지 테스트해야합니다. 그게 다야.

메서드의 코드를 정확하게 테스트 할 수 있습니다. 그러나 그러한 방법은 대개 사적이며 실제로 사적이어야합니다. 그리고 당신은 private 메소드의 코드를 전혀 테스트하지 말아야한다. 당신이 어쨌든 그것을하고 싶다면, 당신의 시험은 당신의 사적 방법에 결합 될 것이고 그것은 좋지 않습니다.

는이 같은 :set_updates을 before_update 테스트 할 수 있습니다 : 당신이 당신의 private 메소드의 코드를 테스트하려면

let(:option) { Option.create("init your params here") } 

it "test callback" do 
    expect(option).to receive(:set_updates) 
    option.save 
end 

, 당신이

let(:option) { Option.create("init your params here") } 

it "test callback" do 
    # expect to receive some messages 
    # which are in your method code 
    # for example 
    expect_any_instance_of(Suboption).to receive(:activity_id=) 
    option.send(:set_updates) 
end 

P.S.처럼 그렇게 할 수 "Rails Conf 2013 Sandi Metz의 테스트 매직 트릭"을보고 듣고 싶을 수도 있습니다. 매우 도움이되는 일입니다.

6

경고 :이 답변은 유감입니다.

구현 방식이 아닌 테스트 동작입니다.

콜백은 구현 세부 사항입니다. 직접 테스트하지 마십시오. 대신 모델이 내부적으로 어떻게 작동하는지 모르고 동작 방식을 테스트하십시오.

내가 제대로 코드를 읽고 있어요 경우는 동작과 같이 설명 할 수 있습니다

옵션을 갱신, 그 하위 옵션의 각각의 activity_id은 는 옵션의 activity_id로 설정됩니다.

옵션을 사용하여 하위 옵션을 만듭니다. 이를 갱신하고 다시로드하고 각 activity_id의 값이 올바른지 점검하십시오.

이것은 조롱보다 느리지 만 부서지기 어렵습니다. 또한 테스트를 작성하고 유지하는 것이 훨씬 쉽습니다.