La imagen anterior muestra la información que nos da CPPUnit de una típica batería de pruebas: varias colecciones, formada cada una de ellas por varios casos de pruebas.
Sin embargo, aunque el ejemplo que aquí hemos desarrollado es el uso típico, CPPUnit permite otros tipos de baterías más complejas.
Por ejemplo, podemos conseguir que no existan colecciones, y mostrar los casos de prueba directamente en el primer nivel, como se muestra en la imagen de la derecha.
Y también podemos hacer que una colección de pruebas contenga a su vez a otra colección, pudiendo así crear estructuras de pruebas anidadas:
Para conseguir esto, debemos cambiar el objeto que retornaremos en el método suite.
Recordemos su prototipo:
Test* DatosDiscoTest::suite()
Podemos ver que el método suite acepta que retornemos un objeto de tipo Test o cualquier descendiente.
Si nos fijarnos bien en la jerarquía de clases de CPPUnit, veremos que tenemos distintos objetos que podríamos retornar desde el método suite.
Vamos a ver algunas de las clases que aparecen en el diagrama y cómo podemos utilizarlas de formas alternativas para modificar la estructura de las pruebas:
-
La clase TestCaller ya la hemos utilizado para crear un test individual y añadirlo a una colección de pruebas. Con esta clase también conseguiremos ejecutar una prueba individual simplemente dando su nombre y el método donde hemos codificado la prueba. Con esto podremos evitar el uso de las colecciones y mostrar pruebas individuales en el primer nivel de nuestra batería de pruebas:
Test* DatosDiscoTest::suite()
{
TestCaller *caller;
caller = new DatosDiscoTestCaller("testLeer",
&DatosDiscoTest::testLeer) );
return (caller);
}
-
La clase TestCase también la hemos utilizado, pero para un uso distinto: como contenedor de todos los métodos que implementan las pruebas. Existe otro uso, que nos permite ejecutar una prueba idividual utilizando un TestCase. Basta con sobrescribir el método runTest y codificar ahí nuestra prueba, tal y como veremos en el siguiente código. Esto nos sirve para el mismo propósito que el código anterior, pero ahorrándonos el uso del TestCaller.
// en el archivo de cabecera
class DatosDiscoTest : public TestCase
{
public:
...
protected:
// en este método codificamos la prueba individual
virtual void runTest(TestResult* r);
};
// en la implementación
Test* DatosDiscoTest::suite()
{
TestCase *prueba;
prueba = new TestCase("DatosDiscoTest");
return (prueba);
}
-
Y por último, la clase TestSuite es la que hemos estado utilizando hasta ahora. Con ella podemos crear una colección de pruebas, configurando previamente el contenido de la colección.
A la hora de añadir el contenido de la colección, debemos usar el método “addTest” de TestSuite, y podremos utilizar como parámetro también cualquier objeto descendiente de Test, tal y como vemos en su prototipo:
void addTest(Test *test);
Esto nos permite añadir tanto un TestCaller (como hemos hecho hasta ahora), un TestCase (si implementamos el método runTest, como ya hemos explicado) o incluso otro TestSuite (porque también es un descendiente de Test). Esto nos permite crear jeraquías de clases, tal y como hemos explicado ya. El código sería algo parecido a lo siguiente:
Test* DatosDiscoTest::suite()
{
TestSuite *suite;
suite = new TestSuite("DatosDisco");
suite->addTest( OtroTest::suite() );
return (suite);
}