Laboratório de Programação - Exercício 30
Testes automáticos João Araujo Ribeiro jaraujo@uerj.br Universidade do Estado do Rio de Janeiro
Resumo
1 Ex30 - Testes automáticos
Exercício 30 - Testes automáticos
Neste capítulo vamos apresentar um pequeno framework para testes, chamado minunit.
c-skeleton/tests/minunit.h 1/2
1 #undef NDEBUG 2 #ifndef _minunit_h 3 #define _minunit_h 4 5 #include <stdio.h> 6 #include <dbg.h> 7 #include <stdlib.h> 89 #define mu_suite_start()char *message = NULL 10
11 #define mu_assert(test, message) if (!(test)) { log_err(message); return message; } 12 #define mu_run_test(test) debug("\n---%s", " " #test); \
13 message = test(); tests_run++; if (message) return message; 14
15 #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 16 argc = 1; \
17 debug("--- EXECUTANDO: %s", argv[0]);\ 18 printf("----\nEXECUTANDO: %s\n", argv[0]);\ 19 char *result = name();\
c-skeleton/tests/minunit.h 2/2
22 }\
23 else {\
24 printf("TODOS OS TESTES OK\n");\
25 }\
26 printf("Tests run: %d\n", tests_run);\ 27 exit(result != 0);\ 28 } 29 30 31 int tests_run; 32 33 #endif
Escrevendo o framework de testes
c-skeleton/tests/libex29_tests.c 1/2
1 #include "minunit.h" 2 3 char *test_dlopen() 4 { 5 6 return NULL; 7 } 8 9 char *test_functions() 10 { 11 12 return NULL; 13 } 14 15 char *test_failures() 16 { 17 18 return NULL; 19 } 20 21 char *test_dlclose() 22 {c-skeleton/tests/libex29_tests.c 2/2
23 24 return NULL; 25 } 26 27 char *all_tests() { 28 mu_suite_start(); 29 30 mu_run_test(test_dlopen); 31 mu_run_test(test_functions); 32 mu_run_test(test_failures); 33 mu_run_test(test_dlclose); 34 35 return NULL; 36 } 37 38 RUN_TESTS(all_tests);RUN_TESTS
O código anterior demonstra o uso da macro RUN_TESTSde minunit.h. Vamos analisar linha por linha.
libex29_tests.c:1
1 #include "minunit.h" Inclui o framework minunit.h.
libex29_tests.c:3-7
1 char *test_dlopen() 2 { 3 4 return NULL; 5 }Um primeiro teste. Testes são estruturados de modo que não tenham argumentos e retornem um char * que é NULL quando tem sucesso. Isto é importante porque as outras macros serão usadas ára retornar uma
libex29_tests.c:9-25
1 char *test_functions() 2 { 3 4 return NULL; 5 } 6 7 char *test_failures() 8 { 9 10 return NULL; 11 } 12 13 char *test_dlclose() 14 { 15 16 return NULL;libex29_tests.c:27
1 char *all_tests() {
A função que controla todos os outros testes. Ela tem a mesma forma que qualquer outro teste, mas vem congurada com outros atributos.
libex29_tests.c:28
1 mu_suite_start();
libex29_tests.c:30-33
1 mu_run_test(test_dlopen); 2 mu_run_test(test_functions); 3 mu_run_test(test_failures); 4 mu_run_test(test_dlclose);
libex29_tests.c:35
1 return NULL;
libex29_tests.c:38
1 RUN_TESTS(all_tests);
Finalmente, apenas usamos a macro RUN_TESTSpara executar todos os testes.
make clean
$ make clean
rm -rf build src/libex29.o tests/libex29_tests rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \; rm -rf 'find . -name "*.dSYM" -print'
Make
$ makecc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -fPIC -c -o src/libex29.o src/libex29.c src/libex29.c: In function `fail_on_purpose':
src/libex29.c:40:33: warning: unused parameter `msg' [-Wunused-parameter] int fail_on_purpose(const char *msg)
^ ar rcs build/libYOUR_LIBRARY.a src/libex29.o ranlib build/libYOUR_LIBRARY.a
cc -shared -o build/libYOUR_LIBRARY.so src/libex29.o
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG build/libYOUR_LIBRARY.a tests/libex29_tests.c -o tests/libex29_tests In file included from tests/libex29_tests.c:1:0:
tests/libex29_tests.c: In function `main':
tests/minunit.h:15:38: warning: parameter `argc' set but not used [-Wunused-but-set-parameter] #define RUN_TESTS(name) int main(int argc, char *argv[]) {\
^
tests/libex29_tests.c:38:1: note: in expansion of macro `RUN_TESTS' RUN_TESTS(all_tests);
^
sh ./tests/runtests.sh Executando a unidade de tests:
----EXECUTANDO: ./tests/libex29_tests TODOS OS TESTES OK
Tests run: 4
Como quebrar o código
Abra o arquivo libex29.so e edite-o com um editor binário. Mude alguns bytes e então o feche. Tente ver se você consegue fazer a função dlopen carregá-lo mesmo estando corrompido.
Trabalho extra
Você prestou atenção ao código ruim que usamos nas funções de
libex29.c? Viu como, mesmo usando um loop for, as funções ainda testam nais com '\0'? Conserte-as para que as funções sempre peguem o tamanho das strings para manipulá-las.
Pegue o diretório c-skeleton e crie um novo projeto para este exercício. Ponha o arquivolibex29.cno diretório src/. Mude oMakefile
para que ele construa ele como build/libex29.so.
Coloque o arquivoex29.ce coloque-o como tests/ex29_tests.c
para que ele possa funcionar como uma unidade de testes.Faça tudo funcionar, o que quer dizer que você deve mudá-lo de modo que ele carregue o arquivo build/libex29.so e execute testes de maneira similar a que zemos na mão.
Leia a documentação de dlopen e suas funções relacionadas. tente algumas das outras opções para dlopen.