【问题标题】:how do I test that an instance variable is set in my my mailer with rspec?如何使用 rspec 在我的邮件程序中测试实例变量是否设置?
【发布时间】:2014-01-31 13:21:24
【问题描述】:

如何使用 rspec 在我的邮件程序中测试某个实例变量是否设置? assigns 回来了 undefined..

require File.dirname(__FILE__) + '/../../spec_helper'

describe UserMailer do

  it "should send the member user password to a User" do
    user = FG.create :user

    user.create_reset_code

    mail = UserMailer.reset_notification(user).deliver

    ActionMailer::Base.deliveries.size.should == 1  

    user.login.should be_present  

    assigns[:person].should == user
    assigns(:person).should == user #both assigns types fail
  end
end

返回的错误是:

undefined local variable or method `assigns' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fe2b88e2928>

【问题讨论】:

    标签: ruby-on-rails rspec instance-variables


    【解决方案1】:

    assigns 仅为 controller 规范定义,这是通过 rspec-rails gem 完成的。 RSpec 中没有测试实例变量的通用机制,但是您可以使用内核的instance_variable_get 来访问您想要的任何实例变量。

    所以在你的情况下,如果 object 是你有兴趣检查其实例变量的对象,你可以这样写:

    expect(object.instance_variable_get(:@person)).to eql(user)
    

    至于获得UserMailer 实例,我看不出有什么办法。查看https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb 中的method_missing 定义,只要调用与实例方法同名的未定义类方法,就会创建一个新的邮件程序实例。但是该实例没有保存在我能看到的任何地方,并且只返回了 .message 的值。以下是目前在 github 上定义的相关代码:

    类方法:

      def respond_to?(method, include_private = false) #:nodoc:
        super || action_methods.include?(method.to_s)
      end
    
      def method_missing(method_name, *args) # :nodoc:
        if respond_to?(method_name)
          new(method_name, *args).message
        else
          super
        end
      end
    

    实例方法:

    attr_internal :message
    
    # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
    # will be initialized according to the named method. If not, the mailer will
    # remain uninitialized (useful when you only need to invoke the "receive"
    # method, for instance).
    def initialize(method_name=nil, *args)
      super()
      @_mail_was_called = false
      @_message = Mail.new
      process(method_name, *args) if method_name
    end
    
    def process(method_name, *args) #:nodoc:
      payload = {
        mailer: self.class.name,
        action: method_name
      }
    
      ActiveSupport::Notifications.instrument("process.action_mailer", payload) do
        lookup_context.skip_default_locale!
    
        super
        @_message = NullMail.new unless @_mail_was_called
      end
    end
    

    【讨论】:

    • 所以 rspec rails 不允许您在邮件程序中测试实例变量? Minitest 确实...
    • 这很有用,除了在这种情况下,我不确定哪些对象会设置这些实例变量。有什么想法吗?
    • 我不确定。通常,当您检查实例变量的值时,您会特别查看一些代码。您要测试 @person 的值是什么代码?
    • 在 mailer 方法中定义,用于生成邮件的视图模板可以访问。
    • 查看更新消息,了解我是如何做到这一点的。 ;-)
    【解决方案2】:

    我认为这是不可能测试的,除非 Rails 更改其实现,以便它实际上提供对 ActionMailer(控制器)对象的访问,而不仅仅是生成的 Mail 对象。

    正如 Peter Alfvin 指出的那样,问题在于它在此处返回“消息”:

    new(method_name, *args).message
    

    而不是像这样返回邮件程序(控制器):

    new(method_name, *args)
    

    rspec-rails 列表中的这个 post 也可能有帮助:

    似乎合理,但不太可能改变。这就是为什么。 rspec-rails 为 rails 提供的测试类提供包装器。导轨 功能测试支持您在上面提出的三个问题,但是 rails 邮件测试是不同的。从 http://guides.rubyonrails.org/action_mailer_basics.html: "测试 mailers 通常涉及两件事:一是邮件被排队, 另一个是电子邮件是正确的。”

    为了支持您希望在邮件规范中看到的内容,rspec-rails 将 必须提供它自己的 ExampleGroup (而不是包装导轨 class),它必须与 rails 的内部紧密绑定。一世 在 rspec-rails-2 中煞费苦心地限制耦合到公共 API,这带来了巨大的回报:我们只有一个案例,其中 rails 3.x 版本需要 rspec-rails 版本(即有一个 突破性变化)。使用 rails-2,几乎每个版本都崩溃了 rspec-rails 因为 rspec-rails 被绑定到内部(rspec-rails' 故障,而不是轨道)。

    如果你真的想看到这种变化,你需要改变它 在 rails 本身中,此时 rspec-rails 将愉快地包装新的 并改进了 MailerTestCase。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-28
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 2022-12-22
      • 1970-01-01
      • 2021-09-17
      • 2018-03-10
      相关资源
      最近更新 更多