Ruby on rails Rails/Rspec:测试延迟的工作邮件

Ruby on rails Rails/Rspec:测试延迟的工作邮件,ruby-on-rails,rspec,delayed-job,Ruby On Rails,Rspec,Delayed Job,只是想知道如何测试actionmailer请求是否实际发送到rspec中的延迟的_作业que 我本以为这很简单,但我的延迟工作队列似乎没有增加。代码如下: 控制器: def create @contact = Contact.new(params[:contact]) if @contact.save contactmailer = ContactMailer contactmailer.delay.contact_message(@con

只是想知道如何测试actionmailer请求是否实际发送到rspec中的延迟的_作业que

我本以为这很简单,但我的延迟工作队列似乎没有增加。代码如下:

控制器:

  def create
    @contact = Contact.new(params[:contact])
      if @contact.save
        contactmailer = ContactMailer
        contactmailer.delay.contact_message(@contact)
        redirect_to(contacts_url)
      else
        render :action => "new"
      end
规格:

在调用控制器之前和之后,Delayed::Job.count都返回0。我已尝试将条件从控制器中取出,但仍然无法使延迟的作业计数递增


感谢您的任何建议-Chee

我认为您的模拟对象在某种程度上引入了一个错误——如果没有看到
mock\u contact
方法的定义,很难准确地说出是如何引入的

在任何情况下,您都可以尝试以下方法:

  it "queues mail when a contact is created" do
    Contact.stub(:new) { mock_model(Contact,:save => true) }
    Delayed::Job.count.should == 0
    post :create, {}
    Delayed::Job.count.should == 1
  end
或者更性感的版本(警告:我总是以不性感的方式结束):


您还可以通过运行作业或关闭队列来测试作业的功能

随时调整配置(即在
before:each
块中)

或者执行保存的作业

Delayed::Worker.new.work_off.should == [1, 0]
我已经愉快地使用这个方法一段时间了。首先,使用RSpec中新的
any_实例
支持,您可以直接测试延迟方法的效果。然而,我发现使用
work\u off
的测试速度很慢

我现在通常做的是:

mock_delay = double('mock_delay').as_null_object
MyClass.any_instance.stub(:delay).and_return(mock_delay)
mock_delay.should_receive(:my_delayed_method)

然后我对
我的延迟方法
有一个单独的规范。这是更快的,而且可能更好的单元测试实践——特别是对于控制器。虽然如果您正在执行请求规范或其他集成级别规范,那么您可能仍然希望使用
关闭

您也可以遵循

但要做到这一点:

    Delayed::Job.last.handler.should have_content(user.email)

这条线有点旧了,但我的做法是:

创建一个函数expect\u jobs

def expect_jobs n, time = nil
  expect(Delayed::Job.count).to eq(n)
  Timecop.travel(time) unless time.nil?
  successes, failures = Delayed::Worker.new.work_off
  expect(successes).to eq(n)
  expect(failures).to eq(0)
  expect(Delayed::Job.count).to eq(0)
  Timecop.travel(Time.now) unless time.nil?
end
然后只需在检查回调是否完成其工作之前调用它。例如:

it "sends a chapter to the admin user" do
  post :chapter_to_user, { chapter: @book.chapters.first}
  expect_jobs(1)
  SubscribeMailer.should have(1).delivery
  SubscribeMailer.deliveries.should have(1).attachment
end

这对我来说似乎很有效,允许我运行延迟的作业和方法。

@zettetic我认为我们必须在这里通过更改方法中的块

应该是这样的:

it "queues mail when a contact is created" do
Contact.stub(:new) { mock_model(Contact,:save => true) }
expect {
    post :create, {}
  }.to change { Delayed::Job.count }.by(1)
end

我喜欢这样。请注意,为了完整性,您还应该(单独)测试延迟的作业是否被添加到delayed_jobs表中。
    Delayed::Job.last.handler.should have_content(user.email)
def expect_jobs n, time = nil
  expect(Delayed::Job.count).to eq(n)
  Timecop.travel(time) unless time.nil?
  successes, failures = Delayed::Worker.new.work_off
  expect(successes).to eq(n)
  expect(failures).to eq(0)
  expect(Delayed::Job.count).to eq(0)
  Timecop.travel(Time.now) unless time.nil?
end
it "sends a chapter to the admin user" do
  post :chapter_to_user, { chapter: @book.chapters.first}
  expect_jobs(1)
  SubscribeMailer.should have(1).delivery
  SubscribeMailer.deliveries.should have(1).attachment
end
it "queues mail when a contact is created" do
Contact.stub(:new) { mock_model(Contact,:save => true) }
expect {
    post :create, {}
  }.to change { Delayed::Job.count }.by(1)
end