2017-01-11 14 views
2

私はモデルのbefore_updateコールバックをテストしようとしています。RspecとFactoryGirlを使用してrailsモデルの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

私は最初から始めようとします。

コールバックをテストするには、コールバックが必要なときに呼び出されることをテストする必要があります。それで全部です。

メソッドのコードを正確にテストしたい場合があります。しかし、そのような方法は通常プライベートであり、実際にはプライベートであるべきです。また、プライベートメソッドのコードをテストするべきではありません。とにかくそれをやりたければ、あなたのテストはあなたのプライベートメソッドに結合され、それは良くありません。

あなたはこのような:set_updatesをbefore_updateテストすることができます。

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の値が正しいことを確認してください。

これは嘲笑よりも遅くなりますが、脆くはありません。また、テストの作成と保守がはるかに簡単です。

関連する問題