Estoy intentando verificar el comportamiento de mi aplicación ASP.Net MVC cuando ocurre un error inesperado. Específicamente, intento verificar que el usuario se dirija a la página de error que he definido para mi aplicación. El problema que estoy enfrentando es que no puedo verificar el comportamiento del método del controlador como se esperaba.¿Cómo puedo probar la unidad el comportamiento del atributo HandleError para un método de controlador?
Para mis pruebas normales de comportamiento, creo un objeto de regla comercial falso y lo paso a mi controlador y luego verifico ViewResult desde el método del controlador que deseo probar. Esto funciona bien para mis propósitos cuando las cosas funcionan como se espera. Sin embargo, cuando lanzo una excepción desde el método de regla comercial, la excepción se lleva a mediante el resultado del método controlador en lugar de manipularla (el controlador tiene el atributo 'HandleError') por el controlador para que ViewResult para que se devuelva mi página de error
¿Hay alguna manera de verificar el comportamiento del atributo HandleError de esta manera? ¿O estoy haciendo esto completamente mal? Me doy cuenta de que podría usar Selenium (prueba en el navegador que afectaría al servidor real) para verificar el comportamiento en un navegador real, pero burlarse de este tipo de pruebas me permite hacerlo más rápido y con mucho menos gastos generales ...
Ejemplo de código de prueba:
// WidgetController.Index() makes a call to GetWidgets to retrieve a
// List<Widget> instance.
// this works as expected since the appropriate ViewResult is returned
// by the controller
public void TestWidgetControllerIndex_NoResultsFound()
{
var mockBR = new Mock<IBusinessRules> { CallBase = true };
mockBR.Setup(br=>fr.GetWidgets()).Returns(new List<Widget>());
WidgetController controller = new WidgetController(mockBR.Object);
ViewResult result = (ViewResult)controller.Index();
Assert.AreEqual("Index", result.ViewName);
Assert.AreEqual(0,
((WidgetIndexViewData)result.ViewData.Model).Widgets.Count);
}
// this test is unable to reach the assertion statements due to the problem
// outlined above. WidgetController.Index has the HandleError attribute
// properly applied and the behaviour via the interface is as expected
public void TestWidgetControllerIndex_BusinessRulesExceptionEncountered()
{
var mockBR = new Mock<IBusinessRules> { CallBase = true };
mockBR.Setup(br=>fr.GetWidgets()).Throws<ApplicationException>();
WidgetController controller = new WidgetController(mockBR.Object);
ViewResult result = (ViewResult)controller.Index();
// The ApplicationException thrown by the business rules object bubbles
// up to the test through the line above. I was expecting this to be
// caught and handled by the HandleError filter (which would then let
// me verify the behaviour results via the assertion below)..
Assert.AreEqual("Error", result.ViewName);
}
te agradecería alguna sugerencia en cuanto a lo que podría estar haciendo mal o si sólo estoy acercarse a esto desde la dirección equivocada por completo. Estoy asumiendo que la prueba en el nivel de método del controlador es la forma adecuada de hacerlo aquí ya que es allí donde se aplica el atributo HandleError. (Si necesito probar a nivel de la aplicación, ¿es posible hacerlo a través de objetos instanciados en lugar de utilizar algo así como el selenio?)
Actualizar he llegado a la conclusión de que no debería estar poniendo a prueba la funcionalidad relacionada con el atributo HandleError en cada acción del controlador. Realmente no me importa lo que hace, solo quiero asegurarme de que se maneje el error (desde mi perspectiva de prueba si su código personalizado o las bibliotecas MVC no hacen la diferencia, es la funcionalidad que quiero verificar)
Lo que he acabado haciendo es ajustar mis acciones de controlador en try/catch blocks para forzar que se devuelva la vista Error como resultado del método (en lugar de que el atributo ErrorHandler capture el error cuando sale del método). De esta forma puedo afirmar en mi unidad que el error se maneja adecuadamente con los comentarios apropiados. No estoy muy satisfecho con la longitud adicional que esto agrega a mis métodos de controlador, pero me permite proporcionar un mensaje de error amigable y específico para el usuario (estoy usando un método de extensión para mostrar los comentarios y realizar el registro). (Así que hay pros y contras del enfoque try/catch para asegurarse ...)
No estoy 100% seguro de que este sea el camino más limpio, pero logra mi objetivo de poder verificar esos errores se manejan a través de pruebas unitarias de controlador (rápido) en lugar de tener que ejecutar pruebas en un navegador (lento). Básicamente es suficientemente bueno por ahora, hasta que pueda encontrar una solución más limpia. He decidido ofrecer una recompensa si alguien encuentra un problema similar y ha encontrado una mejor solución.
Este es exactamente el enfoque que he tomado. (es decir, usar Selenium para verificar el comportamiento a través de una prueba de integración ...) –
¿Esta regla sería la misma cuando personalices el atributo HandleErrorAttribute, por ejemplo, hemos personalizado el HandleErrorAttribute para manejarlo con Elmah? ¿Debo simplemente afirmar en la prueba unitaria si el controlador emite una excepción o no y dejar el elemento Elmah como parte de la prueba de integración que hemos escrito utilizando Selenio? – byte