`object.message if object.respond_to? :message`有效,但证明难以测试

时间:2015-10-19 14:59:13

标签: ruby-on-rails unit-testing ruby-on-rails-4 testing mocking

我在rails应用程序中进行了以下设置:

class Song < ActiveRecord::Base

  after_commit :update_singable_index
  belongs_to :singable, polymorphic: true

  def update_singable_index
    singable.update_index if singable.respond_to? :update_index
  end
end

我已经大量编辑了实际班级。如果需要更多信息,请告诉我。

但基本上Song模型与一堆模型有多态关联。他们中的一些人有弹性研究指数,其中一些人没有。因此,其中一些人会接受update_index消息,而其他人会抛出NoMethodError: undefined method 'update_index'

唱歌工厂看起来像这样:

FactoryGirl.define do
  factory :song do
    album { create(:album) }
  end

  trait :for_updatable do
    updatable_type 'Updatable'
    association :singable, factory: :updatable
  end

  trait :for_unupdatable do
    updatable_type 'Unupdatable'
    association :singable, factory: :unupdatable
  end
end

然后在测试中我有以下设置:

RSpec.describe Song, type: :model do
  describe '.update_index_of_updatable' do
    it 'updates Updatable\'s index' do
      song = create(:song, :for_updatable)
      updatable = song.singable

      expect(updatable).to receive(:update_index)

      song.save
    end

    it 'doesn\'t attempt to update an Unupdatable\'s index' do
      song = create(:song, :for_unupdatable)
      unupdatable = song.singable

      expect(unupdatable).not_to receive(:update_index)

      song.save
    end
  end
end

第一次测试确实通过了。另一方面,第二次测试失败

1) Song.update_singable_index doesn't attempt to update an Unupdatable's index
     Failure/Error: update.save
       (#<Unupdatable:0x0000000b39be98>).update_index(no args)
           expected: 0 times with any arguments
           received: 1 time
     # ./app/models/song.rb:103:in `update_index_of_updatable'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:430:in `block in make_lambda'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:261:in `call'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:261:in `block in simple'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:504:in `call'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:504:in `block in call'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:504:in `each'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:504:in `call'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:88:in `run_callbacks'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/bugsnag-2.8.12/lib/bugsnag/rails/active_record_rescue.rb:8:in `run_callbacks'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:314:in `committed!'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/transaction.rb:89:in `commit_records'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/test_after_commit-0.4.1/lib/test_after_commit.rb:47:in `test_commit_records'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/test_after_commit-0.4.1/lib/test_after_commit.rb:23:in `block in transaction_with_transactional_fixtures'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/test_after_commit-0.4.1/lib/test_after_commit.rb:9:in `transaction_with_transactional_fixtures'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:220:in `transaction'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:286:in `block in save'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:301:in `rollback_active_record_state!'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/activerecord-4.2.3/lib/active_record/transactions.rb:285:in `save'
     # ./spec/models/song_spec.rb:141:in `block (3 levels) in <top (required)>'
     # ./spec/rails_helper.rb:417:in `block (2 levels) in <top (required)>'
     # ./spec/rails_helper.rb:192:in `block (2 levels) in <top (required)>'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/rspec-retry-0.4.2/lib/rspec/retry.rb:52:in `block (3 levels) in apply'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/rspec-retry-0.4.2/lib/rspec/retry.rb:43:in `times'
     # /usr/local/rvm/gems/ruby-2.2.3/gems/rspec-retry-0.4.2/lib/rspec/retry.rb:43:in `block (2 levels) in apply'

1 个答案:

答案 0 :(得分:0)

你没有显示你的:for_unupdatable特征,但它必须是这里有缺陷的部分(意思是,一首歌的singable,这个特性仍然会响应update_index

所以,你应该解决这个问题。

或者,为不支持ES的模型提供该方法的虚拟实现。

class ElasticSearchSingable
  # your regular update_index
end

class SimpleSingable
  def update_index
    # do nothing here, 
    # purpose of this empty method is conformance to common API
  end
end