如何在邮件程序帮助程序方法上设置should_receive期望值?

时间:2013-02-05 10:53:08

标签: ruby-on-rails ruby rspec

我正在将一个模块混合到邮件程序中并将其添加为帮助程序,以便在视图中访问它。我需要测试从视图中调用正确的辅助方法(以便跟踪像素包含在电子邮件中),但Rspec似乎不起作用:

require "spec_helper"

describe DeviseOverrideMailer do

  before :each do
    # Make the helper accessible.

    # This approach does not work
    # class MixpanelExposer; include MixpanelFacade end
    # @mixpanel = MixpanelExposer.new

    # This approach also does not seem to work, but was recommended here: http://stackoverflow.com/questions/10537932/unable-to-stub-helper-method-with-rspec
    @mixpanel = Object.new.extend MixpanelFacade
  end

  describe "confirmation instructions" do
    it "tells Mixpanel" do
      # Neither of these work.
      # DeviseOverrideMailer.stub(:track_confirmation_email).and_return('') 
      @mixpanel.should_receive(:track_confirmation_email).and_return('')

      @sender = create(:confirmed_user)
      @email = DeviseOverrideMailer.confirmation_instructions(@sender).deliver

    end
  end
end

邮件:

class DeviseOverrideMailer < Devise::Mailer
  include MixpanelFacade
  helper MixpanelFacade
end

模块:

class MixpanelFacade
  def track_confirmation_email
    # Stuff to initialise a Mixpanel connection
    # Stuff to add the pixel
  end
end

邮件程序视图(HAML):

-# Other HTML content

-# Mixpanel pixel based event tracking
- if should_send_pixel_to_mixpanel?
  = track_confirmation_email @resource

错误: 它抱怨它无法正确初始化Mixpanel连接(因为缺少请求帮助程序),这表明.should_receive()没有正确地将track_confirmation_email()方法存根。我怎样才能正确地将它拿出来?

2 个答案:

答案 0 :(得分:1)

Rails通过不暴露Mailer的实例来解决这个问题。请注意我们如何在Mailers上定义实例方法,例如def confirmation_instructions(sender) ...,但我们将它们称为类方法,如:DeviseOverrideMailer.confirmation_instructions(@sender)。这可以通过一些method_missing魔法来实现:

# actionmailer-3.2.11/lib/action_mailer/base.rb 
module ActionMailer
  #...
  class Base < AbstractController::Base
    #...
    class << self
      #...
      #line 437
      def method_missing(method, *args) #:nodoc:
        return super unless respond_to?(method)
        new(method, *args).message
      end

注意new(...).message创建的一次性实例。我们的Mailer被实例化,使用和丢弃,让我们没有简单的方法来拦截我们的模拟/存根规范。

我唯一可以建议的是将你想要存根的行为提取到一个单独的类方法和存根中。

# in the helper:
module MixpanelFacade
  def track_confirmation_email
    Utils.track_confirmation_email(@some_state)
  end

  module Utils
    def self.track_confirmation_email(some_param)
      # Stuff to initialise a Mixpanel connection
      # Stuff to add the pixel
    end
  end
end

# in the spec
it "tells Mixpanel" do
  MaxpanelFacade::Utils.stub(:track_confirmation_email).and_return('') 
  @sender = create(:confirmed_user)
  @email = DeviseOverrideMailer.confirmation_instructions(@sender).deliver
end

这肯定是一个黑客攻击 - 我们正在提取一个不必要的类方法,因此我们可以将它存根 - 但我没有遇到任何其他方式来执行它。如果你还没有解决这个问题,那就值得在rspec邮件列表上询问(请告诉我他们的意见:)。

答案 1 :(得分:0)

如果您使用的是更高版本的rspec,我会找到更好的解决方案。

您只需修改邮件程序对象的any_instance_of并存根您想要存根的特定方法即可。

any_instance_of(DeviseOverrideMailer)do | mailer |         //你应该接受这个   端