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 Departamento de Engenharia de Sistemas e Computação João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 1 / 22
Resumo 1 Ex30 - Testes automáticos Trabalho extra João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 2 / 22
Exercício 30 - Testes automáticos Neste capítulo vamos apresentar um pequeno framework para testes, chamado minunit. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 3 / 22
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> 8 9 #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();\ 20 if (result!= 0) {\ 21 printf("falhou: %s\n", result);\ João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 4 / 22
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 João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 5 / 22
Escrevendo o framework de testes Precisamos criar o framework, escrevendo uma unidade de testes vazia. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 6 / 22
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 { João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 7 / 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); João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 8 / 22
RUN_TESTS O código anterior demonstra o uso da macro RUN_TESTS de minunit.h. Vamos analisar linha por linha. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 9 / 22
libex29_tests.c:1 #include "minunit.h" Inclui o framework minunit.h. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 10 / 22
libex29_tests.c:3-7 char *test_dlopen() { } return NULL; 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 mensagem de erro para o programa que executa os testes. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 11 / 22
libex29_tests.c:9-25 char *test_functions() { } return NULL; char *test_failures() { } return NULL; char *test_dlclose() { } return NULL; Mais testes como o primeiro. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 12 / 22
libex29_tests.c:27 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. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 13 / 22
libex29_tests.c:28 mu_suite_start(); Inicializa coisas comuns a todos os testes. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 14 / 22
libex29_tests.c:30-33 mu_run_test(test_dlopen); mu_run_test(test_functions); mu_run_test(test_failures); mu_run_test(test_dlclose); Aqui é para dizer qual teste executar. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 15 / 22
libex29_tests.c:35 return NULL; Após executar os testes, retornamos NULL como qualquer outro teste. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 16 / 22
libex29_tests.c:38 RUN_TESTS(all_tests); Finalmente, apenas usamos a macro RUN_TESTS para executar todos os testes. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 17 / 22
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' João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 18 / 22
Make $ make cc -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 test 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 tests/libex29_tests PASS João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 19 / 22
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. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 20 / 22
Trabalho extra 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 arquivo libex29.c no diretório src/. Mude o Makefile para que ele construa ele como build/libex29.so. Coloque o arquivo ex29.c e 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. João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 21 / 22
Trabalho extra FIM João Araujo Ribeiro (UERJ) Laboratório de Programação LabProg 22 / 22