¿Cómo verifico “no ocurrió ninguna excepción” en mi prueba de unidad MSTest?


88

Estoy escribiendo una prueba unitaria para este método que devuelve "void". Me gustaría tener un caso en el que la prueba pase cuando no se lanza ninguna excepción. ¿Cómo escribo eso en C #?

Assert.IsTrue(????)

(Supongo que así es como debería comprobarlo, pero ¿qué entra en "???")

Espero que mi pregunta sea lo suficientemente clara.


¿Está utilizando MSTest o NUnit?
Matt Grande

2
En MSTest, las excepciones no detectadas harán que las pruebas fallen automáticamente. ¿Está intentando tener en cuenta las excepciones detectadas?
Phil

Puede buscar "try-catch para C #" y eso le indicará cómo manejar las excepciones que se lanzan o no.
Foggzie

1
Si NUnit, mira en Assert.That (lambda) .Throws.N Nothing (aunque creo que eso ha cambiado recientemente)
Matt Grande

Respuestas:


138

Su prueba unitaria fallará de todos modos si se lanza una excepción; no es necesario que ingrese una afirmación especial.

Este es uno de los pocos escenarios en los que verá pruebas unitarias sin ninguna afirmación: la prueba fallará implícitamente si se genera una excepción.

Sin embargo, si realmente deseaba escribir una afirmación para esto, tal vez para poder detectar la excepción e informar "no esperaba ninguna excepción pero obtuve esto ...", puede hacer esto:

[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
    var myObject = new MyObject();

    try
    {
        myObject.MethodUnderTest();
    }
    catch (Exception ex)
    {
        Assert.Fail("Expected no exception, but got: " + ex.Message);
    }
}

(lo anterior es un ejemplo para NUnit, pero lo mismo es válido para MSTest)


Obviamente, no debe ir y detectar tales excepciones para que esto sea cierto.
Servy

7
Una prueba solo fallará si se lanza una excepción no detectada. Dependiendo del código dentro de los manejadores de excepciones, las pruebas unitarias pueden pasar.
código comestible

1
Es útil para Ms Unittest, por lo que no hay un método Assert.DoesNotThrow (() en Unittest.
Başar Kaya

25

En NUnit, puedes usar:

Assert.DoesNotThrow(<expression>); 

para afirmar que su código no lanza una excepción. Aunque la prueba fallaría si se lanza una excepción, incluso si no hubiera Assert a su alrededor, el valor de este enfoque es que luego puede distinguir entre las expectativas no cumplidas y los errores en sus pruebas, y tiene la opción de agregar un mensaje personalizado que se mostrará en su salida de prueba. Una salida de prueba bien redactada puede ayudarlo a localizar errores en su código que han provocado que una prueba falle.

Creo que es válido agregar pruebas para asegurarse de que su código no arroje excepciones; por ejemplo, imagina que estás validando una entrada y necesitas convertir una cadena entrante en una larga. Puede haber ocasiones en las que la cadena sea nula, y esto es aceptable, por lo que debe asegurarse de que la conversión de la cadena no genere una excepción. Por lo tanto, habrá un código para manejar esta ocasión, y si no ha escrito una prueba, se perderá la cobertura de una parte importante de la lógica.


1
El DoesNotThrow explícito es bueno. Si estás acostumbrado a ver a Assert. * En una prueba, podrías pensar que el otro era un vago y se olvidó.
Matt Beckman

¿Hay algún equivalente en vstest o mstest?
Dan Csharpster

1
@DanCsharpster, no creo que lo haya, al menos en MSTest; cuando necesité esta funcionalidad en MSTest en el pasado, hice algo como esto: public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }
Clarkeye

@Clarkeye, esa es una idea interesante. ¡Gracias! Con suerte, aprenderán a copiar mejor NUnit en versiones futuras. También pensé en escribir un adaptador entre vstest y NUnit.
Dan Csharpster

@DanCsharpster, una cosa que quizás quieras echarle un vistazo son las afirmaciones fluidas, que tienen un buen soporte para ShouldThrow y ShouldNotThrow: github.com/dennisdoomen/fluentassertions/wiki#exceptions . Los documentos dicen que es compatible con MSTest (aunque solo lo he usado con XUnit y NUnit). Puede que no haga todo lo que desea, pero puede mezclarlo con las afirmaciones de MSTest de todos modos.
Clarkeye

11

No pruebes que algo no sucede . Es como asegurarse de que el código no se rompa . Eso es algo implícito, todos nos esforzamos por lograr un código que no se rompa ni tenga errores. ¿Quieres escribir pruebas para eso? ¿Por qué solo un método? ¿No desea que se prueben todos sus métodos para que no produzcan alguna excepción ? Siguiendo ese camino, terminarás con una prueba adicional, ficticia y sin aseveraciones para cada método en su base de código. No aporta ningún valor.

Por supuesto, si su requerimiento es para verificar método hace excepciones de captura , lo hace la prueba de que (o marcha atrás un poco, prueba de que no tira lo que se supone que la captura).

Sin embargo, el enfoque / prácticas generales permanecen intactos: no escribe pruebas para algunos requisitos artificiales / vagos que están fuera del alcance del código probado (y probar que "funciona" o "no arroja" suele ser un ejemplo de tal, especialmente en un escenario en el que las responsabilidades del método son bien conocidas).

En pocas palabras: concéntrate en lo que tiene que hacer tu código y pruébalo.


10
-1 Puedo pensar en una funcionalidad positiva que requiere y no se lanza una excepción. Para un método cuyo trabajo es manejar excepciones, registrarlas y tomar acción, sin lanzar la excepción más. Hace un buen punto general, pero luego habla en absoluto como si siempre fuera cierto.
Rob Levine

3
@RobLevine: Entiendo tu ejemplo y me doy cuenta de que escribes pruebas en tales casos. Sin embargo, como ha notado, mi punto de hecho se refería a una práctica más general, por así decirlo, probar lo que se supone que debe hacer su código en lugar de probar lo que su código no hace. He reformulado un poco mi publicación, para que mi punto sea más claro y más cercano a lo que tenía en mente. También le da la oportunidad de reconsiderar su voto. Gracias por la aclaración y perdón por la demora en la respuesta.
km

4
Se eliminó el voto negativo: ¡no estaré tan feliz con el voto negativo la próxima vez!
Rob Levine

4
En nuestro proyecto tenemos la clase htmlvalidator, que arroja excepciones si html no es válido. Por ejemplo, cuando el usuario ingresa (usando la consola) javascript en una combinación rica. Entonces, en mi código de caso, lo que hace mi código es no lanzar una excepción (enfoque de lista blanca) y necesito probar eso.
Machet

1
No estoy de acuerdo con esta respuesta. Probar la ausencia de algo a veces bajo un determinado escenario puede ser una prueba válida.
bytedev

7

Esta clase de ayuda me rascó la picazón con MSTest. Quizás también pueda rayar el tuyo.

[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
    // Arrange
    var factory = new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();

    // Assert
    AssertEx.NoExceptionThrown<FormatException>(() =>
        // Act
        _service.ScheduleJob(scheduler)
    );
}

public sealed class AssertEx
{
    public static void NoExceptionThrown<T>(Action a) where T:Exception
    {
        try
        {
            a();
        }
        catch (T)
        {
            Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
        }
    }
}

@Remco Beurskens: agregar una captura general {} al final de NoExceptionThrown <T> suprimirá otros errores, lo cual no es una consecuencia prevista del método. Este no es un método de propósito general para suprimir todas las Excepciones. Está diseñado para fallar solo cuando se lanza una excepción del tipo conocido.
JJS

1
Esto es muy antiguo ahora, pero Asserttiene un descriptor de acceso de propiedad singleton, Thatque se puede usar como gancho para métodos de extensión. Podría ser más ordenado y más fácil de descubrir tener en Assert.That.DoesNotThrow()lugar de AssertEx.DoesNotThrow(). Esto es solo una opinión.
Richard Hauer

3

Me gusta ver un Assert.Whatever al final de cada prueba, solo por coherencia ... sin uno, ¿puedo estar seguro de que no debe haber uno allí?

Para mí, esto es tan simple como poner Assert.IsTrue(true);

Yo que no me accidentalmente puse ese código en allí, y por lo tanto debería tener la suficiente confianza en una rápida descremada a través de que se trataba de la forma prevista.

    [TestMethod]
    public void ProjectRejectsGappedVersioningByDefault() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
            var sut = new ScriptProject(files);
        });

    }

    [TestMethod]
    public void ProjectAcceptsGappedVersionsExplicitly() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        var sut = new ScriptProject(files, true);

        Assert.IsTrue(true);   // Assert.Pass() would be nicer... build it in if you like

    }

No es lo mismo. Si su código arroja, no se realizará ninguna afirmación y su ejecución de prueba fallará. Desea conectarse al marco de prueba afirmando una condición.
DvS

1

Mi amigo Tim me habló de ExpectedException . Realmente me gusta esto porque es más conciso, menos código y muy explícito que está probando una excepción.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

Puedes leer mucho más sobre esto aquí: Uso de atributo de excepción esperada .


1
el OP no pide una excepción.
Daniel A. White

Voy a dejar esta respuesta aquí. Encontré esta pregunta mientras buscaba en Google cómo probar las excepciones y creo que esta respuesta debe estar aquí. El OP tuvo respuesta a su pregunta hace 7 años. Incluso el enlace a la otra respuesta creo que es útil.
Jess

Buen viejo Tim. 🤔
ruffin
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.