2008-08-19 24 views
9

En mi más me comunicado ASERCIÓN C++ proyecto muy utilizado de la siguiente manera:Casos de prueba VS comunicado ASERCIÓN

int doWonderfulThings(const int* fantasticData) 
{ 
    ASSERT(fantasticData); 
    if(!fantasticData) 
     return -1; 
    // ,,, 
    return WOW_VALUE; 
} 

Sin embargo, la comunidad TDD parece disfrutar haciendo algo como esto:

int doMoreWonderfulThings(const int* fantasticData) 
{ 
    if(!fantasticData) 
     return ERROR_VALUE; 
    // ... 
    return AHA_VALUE; 
} 

TEST(TDD_Enjoy) 
{ 
    ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L)); 
    ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo")); 
} 

Sólo con mi experiencias primeros enfoques me permiten eliminar tantos errores sutiles. Pero los enfoques TDD son una idea muy inteligente para manejar códigos heredados.

"Google" - comparan "PRIMER MÉTODO" con "Camina por la orilla con chaleco salvavidas, nada el océano sin protección".

¿Cuál es mejor? ¿Cuál hace que el software sea robusto?

Respuesta

0

No sé a qué subcomunidad TDD particular hace referencia, pero los patrones TDD que he encontrado utilizan Assert.AreEqual() para obtener resultados positivos o utilizan un mecanismo ExpectedException (por ejemplo, atributos en .NET)) para declarar el error que debe ser observado.

1

No hay ninguna razón por la que su paquete de prueba no pueda detectar aseveraciones como la de doMoreWonderfulThings. Esto puede hacerse ya sea haciendo que su manejador ASSERT soporte un mecanismo de devolución de llamada, o las pruebas afirman que contienen un bloque try/catch.

4

En mi experiencia (limitada) la primera opción es bastante más segura. En un caso de prueba, solo prueba la entrada predefinida y compara el resultado, esto funciona bien siempre que se hayan verificado todos los casos de borde posibles. La primera opción simplemente verifica cada entrada y, por lo tanto, prueba los valores 'activos', filtra los errores muy rápidamente, sin embargo, tiene una penalización de rendimiento.

En Code Complete Steve McConnell nosotros aprende el primer método puede ser utilizado con éxito para filtrar los errores en un depuración acumulación. En la compilación de lanzamiento, puede filtrar todas las aserciones (por ejemplo, con un indicador de compilación) para obtener el rendimiento adicional.

En mi opinión, la mejor manera es utilizar ambos métodos:

Método 1 para coger los valores ilegales

int doWonderfulThings(const int* fantasticData) 
{ 
    ASSERT(fantasticData); 
    ASSERTNOTEQUAL(0, fantasticData) 

    return WOW_VALUE/fantasticData; 
} 

y el método de prueba de 2 de borde de los casos un algoritmo.

int doMoreWonderfulThings(const int fantasticNumber) 
{ 
    int count = 100; 
    for(int i = 0; i < fantasticNumber; ++i) { 
     count += 10 * fantasticNumber; 
    } 
    return count; 
} 

TEST(TDD_Enjoy) 
{ 
    // Test lower edge 
    ASSERT_EQ(0, doMoreWonderfulThings(-1)); 
    ASSERT_EQ(0, doMoreWonderfulThings(0)); 
    ASSERT_EQ(110, doMoreWonderfulThings(1)); 

    //Test some random values 
    ASSERT_EQ(350, doMoreWonderfulThings(5)); 
    ASSERT_EQ(2350, doMoreWonderfulThings(15)); 
    ASSERT_EQ(225100, doMoreWonderfulThings(150)); 
} 
2

Ambos mecanismos tienen valor. Cualquier marco de prueba decente atrapará el assert() estándar de todos modos, por lo que una prueba que cause que la afirmación falle resultará en una prueba fallida.

Normalmente tengo una serie de afirmaciones al comienzo de cada método de C++ con un comentario '// preconditions'; es solo un control de cordura sobre el estado que espero que tenga el objeto cuando se llama al método. Estos encajan muy bien en cualquier marco de TDD porque no solo funcionan en tiempo de ejecución cuando se prueba la funcionalidad, sino que también funcionan en el momento de la prueba.

0

En C++, prefiero el método 2 cuando uso la mayoría de los frameworks de prueba. Por lo general, facilita la comprensión de los informes de fallas. Esto es invaluable cuando se escribe una prueba meses o años después de la prueba.

Mi razón es que la mayoría de los marcos de prueba C++ imprimirán el archivo y el número de línea de donde ocurrió la afirmación sin ningún tipo de información de seguimiento de la pila.Por lo tanto, la mayoría de las veces obtendrá el número de línea de informe dentro de la función o método y no dentro del caso de prueba.

Incluso si la afirmación es capturada y reafirmada por la persona que llama, la línea de notificación estará con la declaración de captura y puede no estar cerca de la línea de caso de prueba que llamó al método o función que afirmó. Esto puede ser realmente molesto cuando la función que afirmó puede haberse usado varias veces en el caso de prueba.

Aunque hay excepciones. Por ejemplo, el marco de prueba de Google tiene una declaración de seguimiento de ámbito que se imprimirá como parte de la traza si se produce una excepción. De modo que puede envolver una llamada a la función de prueba generalizada con el alcance del seguimiento y decir fácilmente, dentro de una línea o dos, qué línea en el caso de prueba exacto falló.

Cuestiones relacionadas