【问题标题】:How can I set a should_receive expectation on a mailer helper method?如何在邮件程序辅助方法上设置 should_receive 期望?
【发布时间】:2013-02-05 10:53:08
【问题描述】:

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

【问题讨论】:

  • 看看DeviseOverrideMailer如何调用track_confirmation_email方法会很有帮助。
  • @an4rcho 编辑添加邮件视图。
  • 马特,我不确定我明白你的目标是什么。您说“我需要测试是否从视图中调用了正确的辅助方法......”这向我表明 view 规范中的期望,但上面的代码正在尝试对辅助方法进行存根在 Mailer 的规范中。自从我查看 rails/rspec-rails 已经有一段时间了,所以我可能会错过这里的重点,但是如果在视图中调用 track_confirmation_email,那么在视图规范中会发生存根,不是吗?
  • 也许我采用了错误的方法,但我一直在使用 email-spec gem 来测试邮件规范中电子邮件的内容。我没有为邮件视图制定单独的视图规范。这可能/可取吗?
  • 我知道这已经很多天了,但是你发现了吗?我终于有机会对此进行了一些研究,但并没有走得太远(rails 在设计时真的没有考虑到测试!)。我确实在下面发布了一个 hacky 解决方法,FWIW。就您的方法而言,我认为您是对的-我将相同的想法应用于控制器规格,但这在这里可能没有意义。此外,从 Dave Chelimsky 的 cmets here 看来,不支持这种不带渲染的规范。

标签: ruby-on-rails ruby rspec


【解决方案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 邮件列表中询问(请让我知道他们说什么:)。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 2012-11-04
      • 1970-01-01
      • 2012-08-08
      相关资源
      最近更新 更多