2008-11-06 10 views
15

Uso el marco de prueba de Boost para probar mi código C++ y me pregunto si es posible probar si una función se confirmará. Sí, suena un poco extraño, pero tengan paciencia conmigo! Muchas de mis funciones comprueban los parámetros de entrada al ingresar, afirmando si son inválidos, y sería útil probarlo. Por ejemplo:Prueba para afirmar en el marco de Boost Test

void MyFunction(int param) 
{ 
    assert(param > 0); // param cannot be less than 1 
    ... 
} 

Me gustaría ser capaz de hacer algo como esto:

BOOST_CHECK_ASSERT(MyFunction(0), true); 
BOOST_CHECK_ASSERT(MyFunction(-1), true); 
BOOST_CHECK_ASSERT(MyFunction(1), false); 
... 

Puede comprobar si hay excepciones que son lanzadas usando la prueba Boost así que me preguntaba si había algunos afirman magia también. ..

+0

Sé que esto es un viejo tema pero añadió una solución que se me ocurrió a mí mismo que ayudó en el trabajo. – grokus

Respuesta

5

No lo creo. Siempre puede escribir su propia afirmación que arroje una excepción y luego use BOOST_CHECK_NOTHROW() para esa excepción.

0

Lo sentimos, pero estás atacando tu problema por el camino equivocado.

"assert" es el engendro del diablo (a.k.a. "C") y es inútil con cualquier lenguaje que tenga las excepciones adecuadas. Es mejor volver a implementar una funcionalidad tipo afirmación con excepciones. De esta forma, realmente tiene la oportunidad de manejar los errores de la manera correcta (incluidos los procedimientos de limpieza adecuados) o activarlos a voluntad (para pruebas unitarias).

Además, si su código se ejecuta alguna vez en Windows, cuando falla una aserción obtiene una ventana emergente inútil que le ofrece depurar/abortar/reintentar. Agradable para pruebas unitarias automatizadas.

Así que hágase un favor y vuelva a codificar una función afirmar que arroja excepciones. Hay uno aquí: How can I assert() without using abort()?

Envuélvalo en una macro para obtener _ _FILE _ _ y _ _ LINE _ _ (útil para la depuración) y listo.

+12

Si cree que esto está utilizando afirma de la manera incorrecta. Asserts solo debe usarse para cosas que deben ser verdaderas o es un error de * programador *, vea el ejemplo dado en la pregunta. Si un programador usa una función de forma incorrecta, le gustaría saberlo lo antes posible. –

+1

Estoy de acuerdo con Andreas. Afirma y, de ser posible, static_asserts no debe ser sustituido por excepciones. Están destinados a detectar errores de programadores. –

+4

¿Y qué haces en caso de error del programador ??? Crash and fail hard? Sé serio, gente. Las afirmaciones son obsoletas, punto. No hay excusa para usarlos en el código moderno. Y a usted "le gustaría saber lo antes posible", entonces simplemente deje de hacer "atrapar (...)". – rlerallut

9

Hay dos tipos de errores que me gusta verificar: invariantes y errores en tiempo de ejecución.

Los invariantes son cosas que siempre deberían ser ciertas, sin importar qué. Para aquellos, uso aseveraciones. Cosas como tu no deberían pasarme un puntero cero para el buffer de salida que me estás dando. Eso es un error en el código, claro y simple. En una compilación de depuración, se afirmará y me dará la oportunidad de corregirlo. En una compilación minorista, provocará una infracción de acceso y generará un minivolcado (Windows, al menos en mi código) o un coredump (Mac/Unix). No hay catch que pueda hacer que tenga sentido tratar con la desreferenciación de un puntero cero. En Windows catch (...) se pueden suprimir las infracciones de acceso y dar al usuario una falsa sensación de confianza de que todo está bien cuando ya han resultado horriblemente mal.

Esta es una razón por la que he llegado a creer que catch (...) es generalmente un olor código en C++ y el único lugar razonable en el que puedo pensar en que está presente está en main (o WinMain) justo antes de generar un núcleo volcar y cortésmente salir de la aplicación.

Los errores de tiempo de ejecución son "No puedo escribir este archivo debido a los permisos" o "No puedo escribir este archivo porque el disco está lleno". Para este tipo de errores, lanzar una excepción tiene sentido porque el usuario puede hacer algo al respecto, como cambiar el permiso en un directorio, eliminar algunos archivos o elegir una ubicación alternativa para guardar el archivo. Estos errores de tiempo de ejecución son corregibles por el usuario. La violación de un invariante no puede ser corregida por el usuario, solo por un programador. (A veces los dos son iguales, pero normalmente no lo son).)

Las pruebas unitarias deben obligar al código a arrojar las excepciones de error en tiempo de ejecución que su código podría generar. Es posible que también desee forzar excepciones de sus colaboradores para garantizar que su sistema bajo prueba sea excepcionalmente seguro.

Sin embargo, no creo que tenga sentido intentar obligar a su código a afirmar contra invariantes con pruebas unitarias.

3

Creo que esta pregunta, y algunas de las respuestas, confunden la detección de errores en tiempo de ejecución con la detección de errores. También confunden la intención y el mecanismo.

Error de tiempo de ejecución es algo que puede ocurrir en un programa 100% correcto. Necesita detección, y necesita informes y manejo adecuados, y debe ser probado. También se producen errores y, para comodidad del programador, es mejor detectarlos antes de tiempo utilizando comprobaciones de condiciones previas o comprobaciones invariables o declaraciones aleatorias. Pero esta es la herramienta del programador. El mensaje de error no tendrá sentido para el usuario ordinario, y no parece razonable probar el comportamiento de la función en los datos que el programa adecuadamente escrito nunca le pasará.

En cuanto a la intención y el mecanismo, se debe tener en cuenta que la excepción no es nada mágico. Hace algún tiempo, Peter Dimov dijo en la lista de correo de Boost (aproximadamente) que "las excepciones no son más que un mecanismo de salto no local". Y esto es muy cierto. Si tiene una aplicación donde es posible continuar después de algún error interno, sin el riesgo de que algo se corrompa antes de la reparación, puede implementar una declaración personalizada que arroje una excepción de C++. Pero no cambiaría la intención, y no haría que las pruebas para afirmar sean mucho más razonables.

12

Al tener el mismo problema, hojeé la documentación (y el código) y encontré una "solución" en .

El Boost UTF usa boost::execution_monitor (en ). Esto está diseñado con el objetivo de capturar todo lo que podría suceder durante la ejecución de la prueba. Cuando se encuentra una afirmación execution_monitor lo intercepta y arroja boost::execution_exception. Por lo tanto, usando BOOST_REQUIRE_THROW puede afirmar el error de una afirmación.

manera:

#include <boost/test/unit_test.hpp> 
#include <boost/test/execution_monitor.hpp> // for execution_exception 

BOOST_AUTO_TEST_CASE(case_1) 
{ 
    BOOST_REQUIRE_THROW(function_w_failing_assert(), 
         boost::execution_exception); 
} 

debe hacer el truco. (Funciona para mí.)

Sin embargo (o renuncias):

  • Funciona para mí. Es decir, en Windows XP, MSVC 7.1, impulso 1.41.0. Es posible que sea inadecuado o roto en su configuración.

  • Puede que no sea la intención del autor de Boost Test. (aunque parece ser el propósito de execution_monitor).

  • Tratará cada forma de error fatal de la misma manera. Podría ser que algo que no sea su afirmación está fallando. En este caso, usted podría perder un error de corrupción de memoria y/o perder una afirmación fallida fallida.

  • Podría fallar en futuras versiones de impulso.

  • Espero que falle si se ejecuta en Configuración de liberación, ya que la afirmación será deshabilitada y se ejecutará el código que la declaración se estableció para evitar . Resultando en un comportamiento muy indefinido.

  • Si, en Release config for msvc, ocurriera algún tipo de aseveración u otro error fatal , no se detectaría. (vea los documentos de execution_monitor).

  • Si usa afirmar o no depende de usted. Me gustan.

Ver:

Además, gracias a Gennadiy Rozental (Autor de prueba Boost), si quieres pasar a leen esto, Gran Obra !!

+0

No funcionó para mí - debian gcc 4.4.6 – sje397

+0

tampoco para mí ubuntu 14.04, boost 1.55, gcc 4.8.2 – RichardBruce

+0

no funcionó para mí gcc 4.8.1 centOs 2.6.x – bjackfly

2

En el trabajo me encontré con el mismo problema. Mi solución es usar una bandera de compilación. Cuando mi marcador GROKUS_TESTABLE está en mi GROKUS_ASSERT se convierte en una excepción y con Boost puede probar las rutas de acceso del código que generan excepciones. Cuando GROKUS_TESTABLE está desactivado, GROKUS_ASSERT se traduce a C++ assert().

#if GROKUS_TESTABLE 
#define GROKUS_ASSERT ... // exception 
#define GROKUS_CHECK_THROW BOOST_CHECK_THROW 
#else 
#define GROKUS_ASSERT ... // assert 
#define GROKUS_CHECK_THROW(statement, exception) {} // no-op 
#endif 

Mi motivación original era ayudar a la depuración, es decir, assert() se puede depurar de forma rápida y excepciones a menudo son más difíciles de depurar en GDB. Mi indicador de compilación parece equilibrar la depuración y la capacidad de prueba bastante bien.

Esperanza esto ayuda

Cuestiones relacionadas