2

我将一个模块混合到一个邮件程序中并将其添加为一个帮助程序,以便在视图中访问它。我需要测试是否从视图中调用了正确的辅助方法(以便跟踪像素包含在电子邮件中),但 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() 方法。我怎样才能让它正确地存根?

4

2 回答 2

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

这当然是一个 hack——我们提取了一个不必要的类方法,以便我们可以将它存根——但我还没有遇到任何其他方法来做到这一点。如果您还没有解决这个问题,那么值得在 rspec 邮件列表中询问(请让我知道他们说了什么:)。

于 2013-02-12T16:14:45.603 回答
0

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

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

any_instance_of(DeviseOverrideMailer) 做 |mailer| //你应该收到这里结束

于 2013-11-19T19:56:29.430 回答