…esto no es un subtítulo…
2015-06-23
Presenté recientemente un sistema elemental de pruebas unitarias para el lenguaje de programación C. Este sistema cubre el caso más simple y común: define una macro que sirve para llamar a una función de prueba unitaria y seguidamente imprimir el resultado con un formato uniforme. Puede echarse en falta la capacidad de mostrar estadísticas, así que cubrimos dicha carencia ayer con un filtro externo en awk. La alternativa, por supuesto, consiste en añadir un poco de complejidad al propio sistema hecho en C. El sistema modificado de pruebas unitarias hace el siguiente trabajo:
Para hacer esto, hace falta declarar y poner a cero unas pocas variables; el sistema de pruebas unitarias tiene definida una macro (init_testsuite) que sirve para este fin. Habría que llamar a esta macro desde la misma función (probablemente main) que seguidamente irá invocando las diferentes pruebas unitarias (mediante la macro run_test), imprimirá el resumen final (mediante la macro print_testsuite_summary) y finalizará el programa devolviendo el código de estado del conjunto de pruebas (la variable testsuite_status). El código reside en el fichero de cabecera test.h y es como sigue:
#ifndef TEST_H
#define TEST_H
/*
* Simple unit testing system for the C programming language.
*
* Usage:
*
* 1) Call init_testsuite(). This creates the following automatic
* variables:
* - unsigned int pass_count: number of tests that passed;
* - unsigned int fail_count: number of tests that failed;
* - unsigned int test_count: number of tests run;
* - int testsuite_status: EXIT_SUCCESS if all tests passed,
* EXIT_FAILURE if any test failed.
*
* 2) For each test, call run_test with a void -> int test function
* that returns 1 if the test passes and 0 if the test fails; run_test
* will print "PASS: " or "FAIL: " and the name of the test function
* to the standard output.
*
* 3) Call print_testsuite_summary(project_name) (where project_name
* is a string) to print some statistics.
*/
#include <stdio.h>
#include <stdlib.h>
#define init_testsuite() unsigned int pass_count = 0; \
unsigned int fail_count = 0; \
unsigned int test_count = 0; \
int testsuite_status = EXIT_SUCCESS;
#define run_test(test) do \
{ \
if ((test)()) \
{ \
puts ("PASS: " #test); \
pass_count = pass_count + 1; \
} \
else \
{ \
puts ("FAIL: " #test); \
fail_count = fail_count + 1; \
testsuite_status = EXIT_FAILURE; \
} \
test_count = test_count + 1; \
} while (0)
#define print_testsuite_summary(project_name) \
printf ("============================================================================\n" \
"Testsuite summary for %s\n" \
"============================================================================\n" \
"# TOTAL: %u\n" \
"# PASS: %u\n" \
"# FAIL: %u\n" \
"============================================================================\n", \
(project_name), test_count, pass_count, fail_count);
#endif /* TEST_H */
Podemos poner a funcionar el código con el siguiente programa que define una prueba que sale bien y una prueba que sale mal:
#include <stdlib.h>
#include "test.h"
int
test_1_equals_1 (void)
{
return 1 == 1;
}
int
test_1_equals_2 (void)
{
return 1 == 2;
}
int
main (int argc, char* argv[])
{
init_testsuite ();
run_test (test_1_equals_1);
run_test (test_1_equals_2);
print_testsuite_summary ("example project");
return testsuite_status;
}
Tras compilarlo y ejecutarlo, obtenemos la siguiente salida:
PASS: test_1_equals_1 FAIL: test_1_equals_2 ============================================================================ Testsuite summary for example project ============================================================================ # TOTAL: 2 # PASS: 1 # FAIL: 1 ============================================================================
El código de error es 1 porque una de las pruebas ha fallado.
Categorías: Informática