CppTest
La peor parte del desarrollo de un programa es determinar que funciona correctamente. Ver que has escrito 1000 lineas y aquello no hace lo que debe es cabreante y es mas cabreante tirarte 3 dias para buscar un error estúpido.
Para evitar o al menos paliar estas cosas, hay una metodologia interesante que se llama test-driven development y que forma parte de la tan cacareada XP (eXtreme Programming).
Esta practica de TDD usa unas herramientas denominadas Unit Test. Unit Test hay para un buen puñado de lenguajes:
- Junit, para Java, de Erich Gamma
- phpUnit
- pyUnit o el modulo unit test para python
- unit++, cutee, cut, cpptest, cppunit y yaktest para C++
- check, una unit test para C
Para mi tfc estoy usando cpptest, principalmente por que tiene una caracteristica que lo diferencia del resto: permite comparar resultados en un intervalo. Esa caracteristica para mi es absolutamente fundamental, ya que todo mi tfc tiene valores en coma flotante y no puedo usar una comparacion de igualdad.
La verdad es que es bastante sencillo de usar. Veamos como se comprueba la clase Coordenadas. Esta clase lo unico que hace es guardar la latitud y longitud de un punto y permite contruir la clase de 3 formas diferentes:
- Teniendo la longitud y la latitud en decimal
- Teniendo la longitud y la latitud en sesagesimal
- Teniendo el par pais/ciudad que previamente existe en una hash
Veamos el ejemplo:
#include <iostream>
#include <stdexcept>
#include <coordenadas.h>
#include <cpptest.h>
class TestCoordenadas: public Test::Suite
{
public:
TestCoordenadas() {
TEST_ADD(TestCoordenadas::constructor1);
TEST_ADD(TestCoordenadas::constructor2);
TEST_ADD(TestCoordenadas::constructor3);
TEST_ADD(TestCoordenadas::constructor4);
}
private:
void constructor1() {
Coordenadas test1(34.32, 12.87);
TEST_ASSERT_DELTA(test1.getLongitud(), 0.598997 ,1e-6);
TEST_ASSERT_DELTA(test1.getLatitud(), 0.224624 ,1e-6);
}
void constructor2() {
Coordenadas test2("Nigeria\\Yola");
TEST_ASSERT_DELTA(test2.getLongitud(),0.217875,1e-6);
TEST_ASSERT_DELTA(test2.getLatitud(), 0.16057,1e-6);
}
void constructor3() {
TEST_THROWS(Coordenadas(194.32, 12.87), std::domain_error);
}
void constructor4() {
short pos1[4]= 12,38,23,00 ;
short pos2[4]= -12,59,32,00 ;
Coordenadas test4(pos1, pos2);
TEST_ASSERT_DELTA(test4.getLongitud(),0.220605 ,1e-6);
TEST_ASSERT_DELTA(test4.getLatitud(), -0.226757,1e-6);
}
};
int main()
{
try
{
Test::Suite ts;
ts.add(std::auto_ptr <Test::Suite> (new TestCoordenadas));
Test::Output* output = 0;
output = new Test::TextOutput(Test::TextOutput::Verbose);
//Test::Output output( Test::TextOutput(Test::TextOutput::Verbose) );
ts.run(*output, true);
}
catch(...)
{
std::cout << "excepcion no esperada\n";
}
return 0;
}
TestCoordenadas::contructor[1 2 4] comprueban que la construccion de la clase es correcta. Creamos una clase y comprobamos que el valor que devuelve getLongitud y getLatitud son correctos y establecemos como intervalo 1e-6. Hay que tener en cuenta que los resultados estan en radianes por que el resto del tfc esta lleno de operaciones de senos y cosenos con las coordenadas. TestCoordenadas::contructor3 comprueba que la creacion de una coordenada que no existe falla y lazan la excepcion pertienente.
En el constructor de TestCoordendas registramos los test que queremos ejecutar y despues en el mail, incluimos TestCoordenadas en la clase Suite y luego ejecutamos la clase suite para que recorra todos las clases de test. La salida que tendriamos seria:
[raul@maxwell: /ionoscom/test]./test TestCoordenadas: 4/4, 100% correct in 0.000280 seconds Total: 4 tests, 100% correct in 0.000280 seconds
y en el caso de que hubiera un error:
[raul@maxwell: /ionoscom/test]./test
TestCoordenadas: 4/4, 75% correct in 0.000272 seconds
Test: constructor1
Suite: TestCoordenadas
File: test.cpp
Line: 21
Message: delta(test1.getLatitud(), 0.224624, 1e-6)
Total: 4 tests, 75% correct in 0.000272 seconds
La salida de cpptest es configurable y puede generar HTML texto, texto locuaz (para aquellos que dominan el ingles, verbose ;).
En codeproject, hay una serie de 5 articulos sobre unit test en C# bastate interesante.