Rails / Rspec:测试delayed_job邮件

只是想知道如何测试动作邮件请求实际上是发送到rspec中的delayed_job que。

我原以为它很简单,但我的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.我已经尝试从控制器中取出条件,但我仍然无法使延迟的作业数增加。

任何建议赞赏 – 欢呼

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

随时调整配置(即在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规范。 这要快得多,而且可能是更好的unit testing实践 – 特别是对于控制器。 虽然如果您正在执行请求规范或其他集成级别规范,那么您可能仍然希望使用work_off

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

你也可以遵循约定(来自Railscast 275 )

  ActionMailer::Base.deliveries.last.to.should == user.email 

但是这样做:

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

@zetetic我认为我们必须在这里传递block in 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 

这个post有点老了,但这是我的意思:

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

这似乎适合我,并允许我运行我的延迟工作我的方法。