ruby on rails - perform - Rails/Rspec: Pruebas de correos delayed_job
rails delayed_job_active_record (5)
Solo me pregunto cómo probar que las solicitudes de actionmailer se envían realmente a la cola delayed_job en rspec.
Habría asumido que era bastante simple, pero mi cola delayed_job no parece ir en aumento. Código abajo:
Controlador:
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
Especulación:
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
Tanto antes como después de la llamada al controlador, Delayed :: Job.count devuelve 0. He intentado quitar el condicional del controlador, pero aún no puedo aumentar el número de trabajos retrasados.
Cualquier sugerencia apreciada - cheer
@zetetic creo que tenemos que pasar el bloqueo en el método de cambio aquí.
Debería ser así:
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
Creo que su objeto simulado está introduciendo un error de alguna manera, es difícil decir exactamente cómo sin ver la definición del método mock_contact
.
En cualquier caso, podrías intentar algo en este sentido:
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
o la versión más sexy ( advertencia: siempre termino haciéndolo de forma no sexy ):
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
Este hilo es un poco viejo, pero aquí está:
Crear una función 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
Luego simplemente llámelo antes de verificar si la devolución de llamada ha hecho su trabajo. p.ej:
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
Esto parece funcionar de mi lado y me permite ejecutar tanto mis trabajos demorados como mis métodos.
También puede probar qué harán los trabajos ejecutándolos o desactivando la puesta en cola.
Ajustar la configuración siempre que lo desee (es decir, en un before :each
bloque).
Delayed::Worker.delay_jobs = false
o realiza tus trabajos guardados
Delayed::Worker.new.work_off.should == [1, 0]
He estado usando este método felizmente por un tiempo. Por un lado, utilizando el nuevo soporte any_instance
en RSpec, puede probar los efectos de los métodos diferidos directamente. Sin embargo, he encontrado que las pruebas que usan work_off
son lentas .
Lo que normalmente hago ahora es:
mock_delay = double(''mock_delay'').as_null_object
MyClass.any_instance.stub(:delay).and_return(mock_delay)
mock_delay.should_receive(:my_delayed_method)
Entonces tengo una especificación separada para my_delayed_method
. Esto es mucho más rápido y, probablemente, una mejor práctica de prueba unitaria, especialmente para los controladores. Aunque si está haciendo especificaciones de solicitud u otras especificaciones de nivel de integración, entonces probablemente todavía quiera usar work_off
.
También puede seguir la convención (de Railscast 275 ) de
ActionMailer::Base.deliveries.last.to.should == user.email
pero en lugar de hacer esto:
Delayed::Job.last.handler.should have_content(user.email)