简体   繁体   中英

Rails Wisper skip listener callback

I use Rails Wisper gem and I want to execute listener callback (which sends email) only during specific tests (where I test email sending). In other tests I don't want to send emails even if in production my callback would send them.

Is it possible with Wisper?

publisher (app/models/order.rb)

class Order < ActiveRecord::Base
  include Wisper::Publisher

  after_save do
    publish(:order_after_save, self)
  end

end

listener/observer (app/observers/mailer_order_observer.rb)

class MailerOrderObserver

  def order_after_save order
    if order.status_id_changed? && order.status.notify?
      # send email
    end
  end
end

subscription (config/initializers/wisper.rb)

Rails.application.config.to_prepare do
  Wisper.clear if Rails.env.development? || Rails.env.test?
  # add observers
  Wisper.subscribe(MailerOrderObserver.new)
end

test (spec/observers/mailer_order_observer_spec.rb)

require 'spec_helper'

describe MailerOrderObserver, type: :model do
  let (:order) { create(:order, :with_items) }

  it 'should send email' do
    order.status = create(:status_released)
    # emails are handled by external service, line below just triggers
    # sending
    expect(order.save).to eq(true)
  end
end

I the test above I want to execute MailerOrderObserver order_after_save callback, but not in any other tests (many "orders" are created and changed what normally would trigger email sending).

I use RSpec as testing framework and FactoryGirl.

Of course creating new Order instances with FactoryGirl triggers mailing, which is also not desired.

I found a solution (any better answer will be appreciated):

  1. Unsubscribe listener in question in RSpec config.before(:suite) block so it won't receive any notifications during the tests.

spec/spec_helper.rb

RSpec.configure do |config|

  config.before(:suite) do
    # unsubscribe observer
    Rails.application.config.to_prepare do
      Wisper.unsubscribe(MailerOrderObserver.new)
    end
  end
end
  1. Subscribe listener only for selected tests.

spec/observers/mailer_order_observer_spec.rb

require 'spec_helper'

describe MailerOrderObserver, type: :model do
  # ! prevents lazy loading
  let! (:order) { create(:order, :with_items) }

  describe '.order_after_save' do
    before do
      Wisper.subscribe(MailerOrderObserver.new)
    end

    it 'should send email' do
      order.status = create(:status_released)
      expect(order.save).to eq(true)
    end
  end
end

This way MailerOrderObserver receives notifications from publisher only when Wisper.subscribe... is executed before the test.

Note that it is convenient to use let! (with exclamation mark) in order to instantiate order before subscribing to the Wisper. This way only one publisher notification is received during test. Using let instead will cause two notifications: one after create... and one caused by order.save .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM