Rails/Rspec:测试延迟作业邮件

Posted

技术标签:

【中文标题】Rails/Rspec:测试延迟作业邮件【英文标题】:Rails/Rspec: Testing delayed_job mails 【发布时间】:2011-09-15 04:35:06 【问题描述】:

只是想知道如何测试 actionmailer 请求实际上是发送到 rspec 中的延迟作业队列。

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

控制器:

  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

规格:

  it "queues mail when a contact is created" do
    expectedcount = Delayed::Job.count + 1
    Contact.stub(:new).with(mock_contact())  mock_contact(:save => true) 
    post :create, :contact => mock_contact
    expectedcount.should eq(Delayed::Job.count)
  end

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

任何建议表示赞赏 - 欢呼

【问题讨论】:

【参考方案1】:

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

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

Delayed::Worker.delay_jobs = false

或执行您保存的工作

Delayed::Worker.new.work_off.should == [1, 0]

我一直很高兴地使用这种方法。一方面,使用 RSpec 中新的any_instance 支持,您可以直接测试您的延迟方法效果。但是,我发现使用work_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)

然后我有一个单独的 my_delayed_method 规范。这要快得多,并且可能是更好的单元测试实践——尤其是对于控制器。虽然如果您正在执行请求规范或其他集成级别规范,那么您可能仍想使用work_off

【讨论】:

我喜欢这种方式。请注意,为了完整起见,您还应该(单独)测试延迟的作业是否被添加到 delay_jobs 表中。【参考方案2】:

我认为您的模拟对象以某种方式引入了错误——如果没有看到 mock_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

或者更性感的版本(警告:我总是以不性感的方式做这件事):

  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

【讨论】:

【参考方案3】:

您也可以遵循

的约定(来自Railscast 275)
    ActionMailer::Base.deliveries.last.to.should == user.email

而是这样做:

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

【讨论】:

【参考方案4】:

这个帖子有点老了,但这是我的尝试:

创建一个函数expect_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

这似乎对我有用,并且允许我运行延迟的工作我的方法。

【讨论】:

【参考方案5】:

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

应该是这样的:

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

【讨论】:

以上是关于Rails/Rspec:测试延迟作业邮件的主要内容,如果未能解决你的问题,请参考以下文章

Rails 3 延迟作业 - 升级到 Rails 3 会中断延迟作业任务

使用延迟作业发送电子邮件时报告错误

Ruby on Rails:延迟的作业无法使用邮件程序并给出路由错误

延迟作业无法在 Rails 应用程序中发送电子邮件。

Rails:延迟作业-> 发送异步邮件时未接收“来自”字段

延迟作业和 Mandrill:未初始化的常量 Mandrill::API