any_instance不是与实例无关的

时间:2015-07-06 06:22:46

标签: ruby-on-rails ruby rspec

我在rails app中测试我的一名工作人员时遇到问题。它看起来像这样:

class UserStatisticsWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  def perform(administration_id = nil)
    administrations(administration_id).find_each do |administration|
      User::StatisticsCalculator.new.recalculate_if_needed(administration.id)
    end
  end

  private

  def administrations(administration_id = nil)
    administration_id.present? ? Administration.where(id: administration_id) : Administration.all
  end
end

用rspec测试它:

require 'spec_helper'

describe UserStatisticsWorker do

  describe 'perform' do
    let!(:administration) { create(:administration) }
    let!(:administration_2) { create(:administration) }

    context 'when administration_id is present' do
      it 'runs User::StatisticsCalculator for one administration' do
        expect_any_instance_of(User::StatisticsCalculator).to receive(:recalculate_if_needed).once

        subject.perform(administration.id)
      end
    end

    context 'when administration_id is not present' do
      it 'runs User::StatisticsCalculator for all administrations' do
        expect_any_instance_of(User::StatisticsCalculator).to receive(:recalculate_if_needed).twice

        subject.perform
      end
    end
  end
end

第二个规范未通过以下错误:

   The message 'recalculate_if_needed' was received by #<User::StatisticsCalculator:85721520 > but has already been received by #<User::StatisticsCalculator:0x0000000a383498>

为什么?

2 个答案:

答案 0 :(得分:1)

非常良好的做法是避免使用any_instance_of,而是在工作中提取私有方法,这些方法可以更容易地进行测试。重构看起来像这样:

class UserStatisticsWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  def perform(administration_id = nil)
    administrations(administration_id).find_each do |administration|
      recalculate_if_needed(administration)
    end
  end

  private

  def recalculate_if_needed(administration)
    User::StatisticsCalculator.new.recalculate_if_needed(administration.id)
  end

  def administrations(administration_id = nil)
    administration_id.present? ? Administration.where(id: administration_id) : Administration.all
  end
end

然后,像这样测试:

require 'spec_helper'

describe UserStatisticsWorker do

  describe 'perform' do
    let!(:administration) { create(:administration) }
    let!(:other_administration) { create(:administration) }

    context 'when administration_id is present' do
      it 'tries to recalculate for the specific administration' do
        expect(subject).to receive(:recalculate_if_needed).once

        subject.perform(administration.id)
      end
    end

    context 'when administration_id is not present' do
      it 'tries to recalculate for all administrations' do
        expect(subject).to receive(:recalculate_if_needed).twice

        subject.perform
      end
    end
  end
end

答案 1 :(得分:1)

问题是你已经在一个实例上设置了两次发生的期望......但实际发生的是它在两个不同的实例上被调用了一次。

即这不是您期待的期望......

请参阅另一个答案,了解您可以尝试的内容。