¿Cómo probar la generación de excepciones en Rails / RSpec?

84

Existe el siguiente código:

def index
    @car_types = car_brand.car_types
end

def car_brand
    CarBrand.find(params[:car_brand_id])
    rescue ActiveRecord::RecordNotFound
        raise Errors::CarBrandNotFound.new 
end

Quiero probarlo a través de RSpec. Mi codigo es:

it 'raises CarBrandNotFound exception' do
    get :index, car_brand_id: 0
    expect(response).to raise_error(Errors::CarBrandNotFound)
end

CarBrand con id igual a 0 no existe, por lo tanto, mi código de controlador genera Errores :: CarBrandNotFound, pero mi código de prueba me dice que no se generó nada. ¿Cómo puedo arreglarlo? ¿Qué hago mal?

malcoauri
fuente

Respuestas:

115

Para especificar el manejo de errores, sus expectativas deben establecerse en un bloque; evaluar un objeto no puede generar un error.

Entonces quieres hacer algo como esto:

expect {
  get :index, car_brand_id: 0
}.to raise_error(Errors::CarBrandNotFound)

Consulte Esperar error para obtener más detalles.

Sin embargo, estoy un poco sorprendido de que no obtenga ninguna excepción en los resultados de sus especificaciones.

Jakob S
fuente
1
@ jakob-s el comportamiento de error esperado que está usando aquí no funciona en las solicitudes del controlador. El get :index, car_brand_id: 0mismo no genera un error.
Ricardo Otero
@RicardoOtero Las cosas pueden haber cambiado, pero por lo que vale, lo hace para mí: gist.github.com/koppen/0e1d0894a908a3768847 . Pero ciertamente, algo en la pila podría estar manejando el error antes de que aparezca en el corredor de especificaciones.
Jakob S
Esta es la respuesta correcta para las versiones actuales de rspec y debe votarse a favor
Neil Woods
Eso es correcto. La forma correcta para probar excepciones es usar {} en lugar de () en el método except.
Luiz Henrique
109

Utilizar en expect{}lugar de expect().

kaleb4eg
fuente
7
Vale la pena señalar que esto resuelve el problema porque la sintaxis {} crea un bloque para monitorear para que se genere la excepción dada. MiniTest tiene requisitos de sintaxis similares al comprobar que un bloque de código genera una excepción.
Argus9
1
Un cambio tan pequeño. Me hizo moler mis ruedas por un tiempo. Gracias por esto.
Josh
4
No lo puedo creer. ¡1 hora de intentarlo y se está convirtiendo ( )en { }! Muchas gracias
Simon Franzen
1
Sí, lo mismo para mí, creo que gasté más :) debido a eso
publiqué la
2
Sé que debería usar comentarios para preguntar ... pero aún así, me gustaría agradecerles por la respuesta. Después de múltiples enfoques finalmente encontré una solución a mi problema.
Florin Lei
18

get :index nunca generará una excepción; más bien, establecerá la respuesta como un error 500 de alguna manera, como lo haría un servidor real.

En su lugar, intente:

it 'raises CarBrandNotFound exception' do
  controller.params[:car_brand_id] = 0
  expect{ controller.car_brand }.to raise_error(Errors::CarBrandNotFound)
end
BroiSatse
fuente
1
¡Me alegra que alguien haya mencionado esto! :) Jakob trató de educarlos de que nunca generará una excepción en la respuesta más votada, pero se enfrentó a una resistencia incorrecta. 👍
Tarek N. Elsamni