Capturando excepciones en MSTest: guía completa de Assert.ThrowsException

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Cómo capturar una excepción en MSTest sin volverse loco?

\n\n

Estás escribiendo pruebas unitarias en C# y de repente te das cuenta: tu método debe lanzar una excepción en una situación determinada. ¿Cómo verificarlo? Si has buscado en Google «How do I use Assert to verify that an exception has been thrown with MSTest», no estás solo: es una de las preguntas más populares en Stack Overflow. Y hoy lo resolveremos de una vez por todas.

\n\n

En este artículo te mostraré todas las formas de verificar excepciones en MSTest: desde el atributo clásico hasta el moderno Assert.ThrowsException. Aprenderás a escribir pruebas limpias y confiables que no fallen en el peor momento. ¡Vamos allá!

\n\n

¿Por qué es importante verificar excepciones?

\n\n

Imagina: tienes un método Divide(int a, int b). Si b = 0, debe lanzar DivideByZeroException. Sin una prueba, te enterarás solo cuando la aplicación falle en producción. Una prueba unitaria con verificación de excepción es tu red de seguridad.

\n\n

En MSTest (framework de pruebas unitarias de Microsoft) hay varios enfoques. Revisaremos cada uno, pero empezaremos por el más moderno y recomendado.

\n\n

Método 1: Assert.ThrowsException (El más correcto)

\n\n

A partir de MSTest V2 (versión 2.x), tenemos el método incorporado Assert.ThrowsException<T>. Es elegante, legible y flexible. La sintaxis es simple:

\n\n
[TestMethod]\npublic void Divide_ByZero_ThrowsDivideByZeroException()\n{\n    // Arrange\n    var calculator = new Calculator();\n\n    // Act & Assert\n    Assert.ThrowsException<DivideByZeroException>(() => calculator.Divide(10, 0));\n}
\n\n

¿Qué sucede aquí? Pasamos una expresión lambda con la llamada al método. MSTest la ejecuta dentro de un bloque try-catch. Si NO se lanza una excepción, la prueba falla. Si se lanza una excepción de otro tipo, también falla. Solo la excepción esperada lleva al éxito.

\n\n

Ejemplo avanzado: verificar el mensaje de la excepción

\n\n

A veces necesitas asegurarte no solo del tipo de excepción, sino también de su mensaje. Para ello, usa la sobrecarga con el parámetro message o verifica las propiedades del objeto de excepción:

\n\n
[TestMethod]\npublic void GetUserById_InvalidId_ThrowsWithCorrectMessage()\n{\n    // Arrange\n    var service = new UserService();\n\n    // Act\n    var exception = Assert.ThrowsException<ArgumentException>(() => service.GetUserById(-1));\n\n    // Assert adicional\n    Assert.AreEqual("Id must be positive", exception.Message);\n}
\n\n

Observa: Assert.ThrowsException devuelve el objeto de la excepción. ¡Esto te permite verificar cualquier propiedad: InnerException, Data, StackTrace (aunque esta última no suele verificarse).

\n\n

Método 2: Atributo [ExpectedException] (Obsoleto, pero aún en uso)

\n\n

Antes (en MSTest V1) se usaba un atributo sobre el propio método de prueba. Se veía así:

\n\n
[TestMethod]\n[ExpectedException(typeof(DivideByZeroException))]\npublic void Divide_ByZero_ThrowsDivideByZeroException_OldWay()\n{\n    var calculator = new Calculator();\n    calculator.Divide(10, 0);\n}
\n\n

¿Parece conveniente? Pero tiene tres problemas:

\n
    \n
  • No se puede verificar el mensaje de la excepción. No sabes si es la excepción correcta.
  • \n
  • Cualquier excepción de ese tipo es éxito. Incluso si se lanza desde otra línea de código (por ejemplo, en Arrange).
  • \n
  • No se puede ejecutar código después de la excepción. El método de prueba se interrumpe inmediatamente.
  • \n
\n\n

Por eso, en proyectos nuevos usa Assert.ThrowsException. El atributo [ExpectedException] está marcado como deprecated (obsoleto) y podría eliminarse en versiones futuras.

\n\n

Método 3: Try-catch manual (Para extremistas)

\n\n

A veces (muy raramente) necesitas

Blogs

Book Recommendations