3. Como funciona?
o Basicamente é um teste que utiliza algum tipo de gerador de
números (pseudo) aleatórios para gerar os casos de teste
rodrigo@ic.ufal.br 3
Gerador de números
pseudo aleatórios
Gerador de casos de
teste aleatórios
seed Conhecimento
do domínio
Software sob teste Oráculo
4. Read
• Lê nbytes e coloca em buf
• Retorna a quantidade de
bytes lida
• -1 caso algo dê errado
• 0 end of file
• Pode retornar um número
menor que nbytes, nesse caso,
significa: “tente de novo”, mas
não significa que deu erro
rodrigo@ic.ufal.br 4
5. read_all
o Vamos mudar o comportamento padrão do read para evitar
esse retorno que pode ou não retornar o tamanho todo
o A gente vai construir um read_all que usa o read e sempre
retorna a quantidade de bytes lida
o Ou seja, se o read retornar um número menor, a gente tenta de
novo até que ele retorne tudo
rodrigo@ic.ufal.br 5
6. read_all
ssize_t read_all(int file_desc, void *buff, size_t nbytes)
{
assert(file_desc >=0);
assert(buff);
assert(nbytes>=0);
size_t left = nbytes;
while (1)
{
int res = read(file_desc,buff,nbytes);
printf("%dn",res);
if (res < 1)
{
return res;
}
buff+=res; //desloca o ponteiro de "res" bytes
left -= res;
assert (left >=0);
if (left == 0)
{
return nbytes;
}
printf(“Precisando ler de novo!”);
}
}
rodrigo@ic.ufal.br 6
7. read_all :: comentários
o Inicialmente, considera que a quantidade de bytes que faltam
ser lidos é o número de bytes que você pediu para ele ler
o size_t left = nbytes;
o A cada chamada ao read, como ele retorna o número de bytes
lidos, a gente subtrai da quantidade de bytes que faltam
oint res = read(file_desc,buff,nbytes);
...
left -= res;
rodrigo@ic.ufal.br 7
8. main () :: ideias
o Para testar, vamos fazer o seguinte:
oUtilizaremos outra função para ler arquivo, da biblioteca stdio
oIremos ler o arquivo através dela e depois comparar com a nossa
leitura do arquivo
oE vamos fazer isso várias vezes, para tentar fazer com que o read do
read_all de fato não retorne a quantidade de bytes total
oSe ele toda vez retornar a quantidade total de bytes lidos e se o
conteúdo retornado pelo read_all for igual ao retornado pelo fread do
stdio, tudo ok!
rodrigo@ic.ufal.br 8
9. main()
int main()
{
srand( time(NULL));
// abre o arquivo e obtem um file descriptor
int fd = open("arquivo.txt",O_RDONLY);
assert (fd>=0);
struct stat buf;
// recupera informacoes sobre o arquivo
int res = fstat(fd, &buf);
assert (res==0);
// dentre elas, o tamanho
off_t len = buf.st_size;
// aloca espaço para guardar o conteudo
char *definitive = (char *) malloc(len);
assert(definitive);
// lê e armazena o conteúdo em definitive
FILE *file = fopen("arquivo.txt", "rt");
res = fread(definitive, sizeof(char), len / sizeof(char), file);
assert (res == len);
int i;
// cria outra variavel para guardar o conteudo
char *test = (char *) malloc (len);
for (i=0 ; i<10; i++)
{
res = lseek(fd, 0, SEEK_SET);
assert (res==0);
int j;
// preenche ela com lixo
for (j=0; j<len ; j++)
{
test[j] = rand();
}
// chama a funcao de leitura
res = read_all(fd, test, len);
assert(res==len);
// compara a nossa com a anterior
assert(strncmp(test,definitive,len)==0);
}
printf("fimn");
return 0;
rodrigo@ic.ufal.br 9
10. Executando
o Veja que ele não deve ter dado nenhum erro
o Mas provavelmente está sempre imprimindo o número total de
bytes do arquivo
oOu seja, não simulamos o cenário onde o read retorna uma quantidade
de bytes menor
oVeja que, provavelmente, ele não executou o comando da função
read_all:
o printf(“Precisando ler de novo!”);
rodrigo@ic.ufal.br 10
11. Como simular que o read irá retornar menos bytes que
o esperado?
o Não temos nenhum controle sobre a função read()
o Então, como fazer para simular que ela irá retornar menos bytes
em algo que não temos controle?
oFault Injection poderia ser uma alternativa
rodrigo@ic.ufal.br 11
13. E mudar a read_all
…
while (1)
{
int res = read_fi(file_desc,buff,nbytes);
printf("%dn",res);
if (res < 1)
…
rodrigo@ic.ufal.br 13
14. Execute
o E aí, o que achou?
o Você está mais confiante agora que a sua função read_all
funciona bem?
o Como o que acabamos de fazer se “encaixa” no loop que
mostramos no início?
rodrigo@ic.ufal.br 14
16. Como gerar entradas válidas?
o Imagine que vamos testar um browser
o Imagine também que iremos gerar entradas totalmente
aleatórias
rodrigo@ic.ufal.br 16
17. Entradas aleatórias
o Se a entrada for totalmente aleatória, geraremos pouquíssimas
páginas htmls válidas
rodrigo@ic.ufal.br 17
19. Vamos colocar a mão na massa
o Você está desenvolvendo um sistema de pagamentos
o Que irá aceitar também o pagamento por cartões de crédito
o Para testar o que você está fazendo, você irá precisar de
números de cartões de créditos válidos e também inválidos
rodrigo@ic.ufal.br 19
20. (cont.)
o Então, você tem a ideia de gerar números de cartões de crédito
o Mas se você gerar números totalmente aleatórios, muito
dificilmente você gerará um número válido
o Ou seja, seu gerador precisará ser guiado para gerar números
válidos
rodrigo@ic.ufal.br 20
21. Um cartão de crédito
rodrigo@ic.ufal.br 21
Esse check digit é calculado
Usando o algoritimo de Luhn
23. Caso o número de dígitos seja par
rodrigo@ic.ufal.br 23
o Dobre os índices ímpares, ao invés dos pares
24. Agora o check digit
o Você receberá o issue identifier
o Gerará o account number de forma aleatória
o Colocar 0 no check digit
o E calcular a check sum (em cima de todos os dígitos, incluindo o
issue identifier)
o Se for 0, beleza, você já tem um número válido
o Senão
o Basta fazer check_digit = 10 - checksum
rodrigo@ic.ufal.br 24
25. Exemplo
o Issue identifier: 1645
o Suponha um account number de 5 dígitos, gerados aleatoriamente: 83276
o Seu número do cartão até agora: 164583276
o Adicionando o dígito do checksum como 0:
o 1645832760
o Somando:
o (2*6-9) + (2*5-9) + (2*3) + (2*7-9) = 3+1+6+5 = 15
o Checksum = 15%10 = 5, ou seja, não deu zero, logo basta trocaro o checksum por 10-5 = 5
o Número final: 1645832765
rodrigo@ic.ufal.br 25
26. Missão: implementar o generate
def luhn_checksum(n):
assert(n.isdigit())
result = luhn_sum(n) %10
return result
def is_luhn_valid(n):
return luhn_checksum(n)==0
# size is the total size
def generate(pref,size):
return
rodrigo@ic.ufal.br 26
28. Reflexões
o Veja que deu um pouco de trabalho construir um gerador de
casos de testes aleatórios que gera valores válidos de entrada
o Vale a pena?
oLembre do gráfico de validade da entrada
o Se você ignorar o problema de validade da entrada,
provavelmente a maioria dos seus testes irá falhar e será inútil
rodrigo@ic.ufal.br 28