如何使用rspec测试在我的mailer中是否设置了实例变量



如何使用rspec测试某个实例变量是否设置在我的mailer中?赋值返回时未定义。。

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>

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

因此,在您的情况下,如果object是您感兴趣检查其实例变量的对象,则可以编写:

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

至于获得UserMailer实例,我看不出有任何方法可以做到这一点。查看内部的method_missing定义https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb,只要调用与实例方法同名的未定义类方法,就会创建一个新的mailer实例。但该实例并没有保存在我能看到的任何地方,只返回了.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

我认为这是不可能测试的,除非Rails改变其实现,使其真正提供对ActionMailer(控制器)对象的访问,而不仅仅是生成的Mail对象。

正如彼得·阿尔文所指出的,问题是它在这里返回了"信息":

new(method_name, *args).message

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

new(method_name, *args)

rspecrails列表上的这篇文章可能也很有帮助:

看起来合理,但不太可能改变。原因如下。rspec轨道提供了rails提供的测试类的包装器。轨道功能测试支持你上面提出的三个问题,但是rails邮件测试不同。从…起http://guides.rubyonrails.org/action_mailer_basics.html:"测试邮件通常涉及两件事:一是邮件已排队,另一个是电子邮件是正确的。">

为了支持您希望在mailer规范中看到的内容,rspecrails将必须提供自己的ExampleGroup(而不是包裹轨道类),必须将其紧密绑定到rails的内部。我在rspec-rails-2中煞费苦心地将耦合约束到公共API,这带来了巨大的回报:我们只有一个案例rails 3.x的发布需要rspec rails的发布(即断裂变化)。有了rails-2,几乎每一次发布都失败了因为rspec rails已绑定到内部(rspec rails故障,而不是轨道)。

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

最新更新