这个Rspec中使用Class.new有什么好处?

5

我正在阅读一些由已离职的人编写的 Rspec。我对这行代码感到困惑:

  let(:mailer_class) { Class.new(AxeMailer) }
  let(:mailer) { mailer_class.new }

  describe '#check' do
    before do
      mailer_class.username 'username'
      mailer.from 'tester@example.com'
      mailer.subject 'subject'
    end
    subject { lambda { mailer.send(:check) } }

它正在测试这个类:

class AxeMailer < AbstractController::Base

  def self.controller_path
    @controller_path ||= name.sub(/Mailer$/, '').underscore
  end

我想知道这个和let(:mailer_class) { AxeMailer }之间的区别。

我问这个问题是因为当我运行测试时,它会抱怨name为空。但如果我更改它,测试就能通过。

我认为这个问题始于使用Rails 3.2,并且我认为name是从AbstractController::Base继承来的。

在控制台中也是如此(意味着不是Rspec特定的),我可以毫无错误地执行AxeMailer.name,但是如果我执行Class.new(AxeMailer),就会出现问题。

我的问题是:

  1. 为什么要使用Class.new(AxeMailer)而不是AxeMailer
  2. 如果我只是更改这个,是否存在问题?
  3. 有没有一种方法可以不更改规范而使其通过?

你能除了 let 方法之外,再发布更多的测试代码吗?这将有助于我们确定为什么要以这种方式编写它。 - Derek Harmel
刚刚添加了一些,这样够了吗? - lulalala
Class.new(AxeMailer) 创建了一个未命名的类,继承自AxeMailer。虽然这里好像不需要它。http://apidock.com/ruby/Class/new/class - besen
谢谢,所以我猜这基本上是用于测试类继承的?行为不同的原因是什么? - lulalala
2个回答

2

我猜测这是因为 mailer_class.username 'username' 这一行的原因。如果你直接使用 AxeMailerusername 设置将在测试之间传递。通过为每个测试创建一个新的子类,您可以确保它们之间不会传递任何状态。


我认为这可能是原因(反正也不那么重要)。我将其修改为:@controller_path ||= parent.name.sub(/Mailer$/, '').underscore,现在似乎可以通过。 - lulalala

0

我不确定 mailer_class 是否在实际规范中使用,但这是我认为您的设置应该看起来像什么:

let(:mailer) { AxeMailer.new }

describe '#check' do
  before do
    AxeMailer.username 'username'
    mailer.from 'tester@example.com'
    mailer.subject 'subject'
  end
  subject { lambda { mailer.send(:check) } }

似乎没有必要创建匿名类。此外,这只是我的意见,但是您的subject看起来有点奇怪。如果需要,您的规范应该在lambda中包装主题,但不要在subject中这样做。

关于您最初遇到的错误,匿名类没有名称:

1.9.3-p0 :001 > Class.new.name
 => nil 

在ActionMailer::Base的某些部分必须尝试使用类名进行某些操作(例如日志记录),并且当它为nil时会出现错误。


谢谢。name 在方法 self.controller_path 中被使用。它覆盖了 AbstractController::Baseself.controller_path。由于它正在新建一种 AbstractController::Base,所以它也应该可以工作(并且之前一直在工作)。 - lulalala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接