¿Debo seguir usando Debug.Assert hoy?

23

Recientemente me encontré con un código recién escrito que estaba intercalado con muchos Debug.Assert (C #).

¿Deberíamos usar esto ampliamente a pesar del uso de TDD, BDD y Unit Testing en general?

Dominik Fretz
fuente
99
No puedo ver cómo uno excluye al otro.
SuperM
2
@superM Definitivamente he visto a desarrolladores flojos agregar pruebas como afirmaciones antes, ya que habían escrito su código de tal manera que era difícil burlarse de las dependencias. no hace falta decir que no recomendaría esto
jk.

Respuestas:

23

No veo ninguna razón por la que no deberías usar Assert. Al hacerlo, ya ha reconocido la necesidad de guardias, como condiciones previas e invariantes, y está avanzando hacia el Diseño por contrato . Afirmar es solo una forma de lograr esto ...

// Precondition using Asert
void SomeMethod(Foo someParameter)
{
    Debug.Assert(someParameter != null)
}

// Precondition using If-Then-Throw
void SomeMethod(Foo someParameter)
{
    if (someParameter == null)
        throw new ArgumentNullException("someParameter");
}

// Precondition using Code Contracts
void SomeMethod(Foo someParameter)
{
    Contract.Requires(someParameter != null);
}

// Precondition using some custom library
void SomeMethod(Foo someParameter)
{
    Require.ArgumentNotNull(() => someParameter);
}

Todas son formas de lograr lo mismo: robustez en el código. Simplemente se reduce a elegir una opción, de la cual Assert es una opción válida.

Tenga en cuenta que hasta ahora no he mencionado las pruebas unitarias, ya que logran algo muy diferente. Una prueba unitaria demuestra formalmente la solidez del código al ejercer una protección:

[Test]
void SomeMethod_WhenGivenNull_ThrowsArgumentNullException()
{
    delegate call = () => someObject.SomeMethod(null);

    Assert.That(call).Throws<ArgumentNullException>();
}

Este es un tipo de afirmación completamente diferente ...

** Tenga en cuenta que, en algunos marcos, en realidad es bastante difícil hacer una prueba de unidad para un fallo de aserción, ya que un fallo de aserción puede reducir todo el tiempo de ejecución, por lo que podría preferirse una de las otras opciones ... *

MattDavey
fuente
10

Considero que las afirmaciones y las pruebas unitarias son dos herramientas diferentes en mi caja de herramientas. Algunas cosas se adaptan mejor a una, y otras se adaptan mejor a la otra.

A modo de ejemplo, en estos días utilizo principalmente afirmaciones para validar parámetros para métodos no públicos.

vaughandroid
fuente
5

Veo Debug.Assert como una optimización prematura hoy en día. A menos que realmente necesite el rendimiento, la supresión de Assert en modo de liberación puede ocultar errores por más tiempo.

Como MattDavey señala, los contratos de código pueden ser superiores, proporcionando una comprobación estática en lugar de una comprobación dinámica, y si no está disponible, preferiría Trace.Assert o un viejo y simpleif(x) throw SomeException;

jk.
fuente
44
Vale la pena mencionar que generar código con Visual Studio en modo de lanzamiento hará que todas las llamadas a los métodos de la Debugclase se salten de la compilación ... por lo que suprimir las llamadas Assertsimplemente por rendimiento no es solo una optimización prematura, es una tontería.
Konamiman
@Konamiman ese es el punto, casi siempre quiero que falle de la misma manera en el modo de lanzamiento:. Debug.Assert no me sirve el 97% del tiempo
jk.
¿Qué es ese 3% entonces, @jk? ¿Solo código heredado o alguna otra instancia?
DougM
Código crítico de rendimiento de @DougM, es una referencia a la cita de Knuth. También agregaría que creo que el error de heartbleed demuestra que mi punto de vista es el correcto, a menos que no tenga otra opción, no evite las verificaciones de precondición en su código de lanzamiento
jk.