rails perform now job delayed_job_active_record active ruby-on-rails rspec delayed-job

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)