Как шпионить за один вызов ActiveSupport :: Уведомления #instrument, не все из них - PullRequest
0 голосов
/ 29 января 2019

Я делаю тест Rspec, который проверяет, был ли вызван ActiveSupport::Notification.instrument с некоторыми параметрами.

Дело в том, что для того, чтобы сделать этот тест, нужно FactoryBot построить несколько объектов, но когдаЯ пытаюсь шпионить за ActiveSupport::Notification.instrument Я всегда получаю сообщение об ошибке:

ActiveSupport::Notifications received :instrument with unexpected arguments
         expected: (:asd)
              got: ("factory_bot.run_factory", {:factory=>#<FactoryBot::Factory:0x005569b6d30, @al... nil, dispatch: nil, distribution_state: 2, main_category_id: nil>}, :strategy=>:build, :traits=>[]})

Кажется, что FactoryBot вызывает activesupport, поэтому, когда я высмеиваю его в целях тестирования, я в конечном итоге высмеиваю его слишком далеко ...

пример кода:

класс:

class SomeObject
    def initialize(something)
        #some code
    end

    def my_method
        ActiveSupport::Notifications.instrument :asd
    end
end

spec:

describe "#my_method" do
    let(:some_object) { build :some_object }
    before do
      allow(ActiveSupport::Notifications).to receive(:instrument).with :asd
    end

    it "calls notifier" do
      described_class.new(some_object).my_method

      expect(ActiveSupport::Notifications).to have_received(:instrument).with :asd
    end
  end

Как я могу просто высмеивать мой вызов, а не FactoryBot.

Я справляюсь с этим только с одним allow перед тем, который высмеивает :asd:

 allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original

Есть ли другой (лучший) способ?

1 Ответ

0 голосов
/ 29 января 2019

Я склонен избегать насмешек вообще.

У меня была похожая проблема, и вот как я ее достиг:

  describe "#my_method" do
    let(:some_object) { build :some_object }

    before { record_events }

    it "calls notifier" do
      described_class.new(some_object).my_method

      # Make sure your event was triggered
      expect(events.map(&:name)).to include('asd')

      # Check number of events
      expect(events).to be_one

      # Check contents of event payload                  
      expect(events.first.payload).to eq({ 'extra' => 'context' })

      # Even check the duration of an event
      expect(events.first.duration).to be < 3
    end

    private

    attr_reader :events

    def record_events
      @events = []
      ActiveSupport::Notifications.subscribe(:asd) do |*args| #
        @events << ActiveSupport::Notifications::Event.new(*args)
      end
    end
  end

Преимущества над насмешками

  • Больше никаких странных побочных эффектов
  • Использование ActiveSupport::Notifications по назначению
  • ActiveSupport::Notifications::Event обертка дает вам приятные дополнения, такие как #duration
  • Легко проверять наличие других событий, вызываемых
  • Возможность просматривать только те события, которые соответствуют имени - используйте ActiveSupport::Notifications.subscribe(/asd/) для частичного сопоставления имен событий
  • Улучшенная читаемость - проверка событийМассив более читабеленесли вы не очистите @events на teardown
...