Contenido

Atheist: Probando módulos C

Vamos a usar Atheist con el módulo CxxTest , de manera que podamos probar un programa C.

Recordemos algo que yo olvidé: Atheist es una herramienta para pruebas de integración (que tiene como algo adicional la posibilidad de integrarse con python-testunit). Eso quiere decir que nuestras pruebas estarán en C, pero las llamaremos desde Atheist.

Testing

Para comenzar, escribimos nuestras pruebas C. Primero sólo vamos a comprobar la interacción entre Atheist y CxxTest (lo saco de los ejemplos de Atheist):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// archivo single_ok.cc
#include <cxxtest/TestSuite.h>
class MyTestSuite : public CxxTest::TestSuite
{
public:
   void testAddition( void )
   {
      TS_ASSERT( 1 + 1 > 1 );
      TS_ASSERT_EQUALS( 1 + 1, 2 );
   }
};

Ahora creamos el archivo de pruebas atheist:

1
2
#archivo cxxtest.test
CxxTest("$testdir/single_ok.cc", )

Y ejecutamos:

1
2
3
4
$ atheist .
[ OK ] TaskCase: ./cxxtest.test
[  ALL OK!  ] - 1.28s - 1 test - 1 task
$

Un ejemplo más real

Ahora voy a probar un ejemplo algo más real. Voy a hacer una pequeña función que calcula el factorial de un número. Para ello, necesitaré un archivo con mi función, un archivo de cabecera con la declaración de mi función, y el archivo de pruebas. Vamos al lío:

Archivo factorial.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// archivo factorial.h
#ifndef FACTORIAL_H
#define FACTORIAL_H

#ifdef  __cplusplus
extern "C" {
#endif

int factorial (int n);


#ifdef __cplusplus
}
#endif

#endif

Archivo factorial.c

1
2
3
4
5
6
//factorial.c
#include "factorial.h"

int factorial (int n) {
  return n > 1 ? n * factorial (n-1) : 1;
}

Archivo factorial.cc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// archivo test_factorial.cc
#include <cxxtest/TestSuite.h>
#include "factorial.h"
class MyTestSuite : public CxxTest::TestSuite
{
public:
  void test_factorial_1(void)
  {
    TS_ASSERT_EQUALS ( factorial(1), 1 );
  }

  void test_factorial_2(void)
  {
    TS_ASSERT_EQUALS ( factorial(2), 2 );
  }

  void test_factorial_3(void)
  {
    TS_ASSERT_EQUALS ( factorial(3), 6 );
  }

  void test_factorial_4(void)
  {
    TS_ASSERT_EQUALS ( factorial(4), 24 );
  }

};

Archivo cxxtest.test:

1
2
3
4
5
6
7
#archivo cxxtest.test
CxxTest(''$testdir/single_ok.cc'', )


CxxTest(''$testdir/test_factorial.cc'',
        compiling_flags=''-I$testdir'',
        objs={''$testdir'': [''factorial.o'']})

Tened en cuenta que, para ejecutarlo, necesitaremos compilar factorial.o, por lo que tendremos:

1
2
3
4
5
$ gcc -c factorial.c -o factorial.o
$ atheist cxxtest.test -e
[ OK ] TaskCase: ./cxxtest.test
[  ALL OK!  ] - 2.47s - 2 tests - 2 tasks
$

Unas explicaciones

Cuento un poco algunas cosas “raras” que se ven en el código.

Por un lado, vemos que en el archivo factorial.h Hemos incluido unas marcas extrañas:

1
2
3
4
5
6
7
8
9
#ifdef  __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

Esto se hace así para que C++ “entienda” que lo que se va a definir ahí es C. Cuando compilamos código C++, las funciones se renombran añadiéndoles un prefijo y un sufijo, por lo que hay que indicarle que eso es código C para que el compilador pueda encontrar las funciones.

Por otra parte, hemos necesitado indicarle a Atheist algunos parámetros extra, como son los flags de compilación (sólo hemos necesitado la ruta de los .h), y qué objetos se han utilizado.

Transformando Atheist en una herramienta de generación

No es lo más recomendable, pero podríamos usar Atheist para compilar:

1
2
3
4
5
6
7
8
9
#archivo cxxtest.test
CxxTest(''$testdir/single_ok.cc'', )


Command( ''CC=g++ make  $testdir/factorial.o'', shell=True)

t = CxxTest(''$testdir/test_factorial.cc'',
        compiling_flags=''-I$testdir'',
        objs={''$testdir'': [''factorial.o'']})

Detección de errores

Es normal que ocurra algún problema en la ejecución de CxxTest, ya que realiza pasos muy complejos. Por ello recomiendo utilizar siempre Atheist con las opciones “-e” (mostrar salida de error) y “-o” (mostrar salida estándar).

De esta manera será más sencillo descubrir errores de compilación de CxxTest.