Rails/Rspec:测试延迟发送的电子邮件

24

想知道如何在RSpec中测试ActionMailer请求是否实际发送到了delayed_job队列。

我原本认为这很简单,但我的delayed_job队列似乎没有增加。以下是代码:

控制器:

  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。我尝试将条件从控制器中去掉,但我仍然无法使延迟作业计数增加。

欢迎提出任何建议 - 谢谢!

5个回答

48

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

随时调整配置(例如在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


我喜欢这种方式。请注意,为了完整性,您还应该(单独)测试延迟作业是否被添加到delayed_jobs表中。 - brittohalloran

16

我认为你的模拟对象在某种程度上引入了一个错误,没有看到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

9
你可以按照约定的方式进行(来自Railscast 275),示例如下:
    ActionMailer::Base.deliveries.last.to.should == user.email

而是应该做这个:

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

0

@zetetic 我认为我们必须在这里传递一个块变量到change方法中。

应该是这样的:

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

0
这个帖子有点老了,但是我来试着回答一下:
创建一个函数 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

这在我的端上似乎可以工作,并且允许我运行我的延迟任务和方法。


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