3. Ubuntu release
o Ubuntu 12.04 LTS
oA primeira release
estável só começou no
.04
o Logo depois do
lançamento
oBugs, bugs e mais bugs
rodrigo@ic.ufal.br 3
4. Não é assim com quase todos os software
o Por que que os desenvolvedores lançam uma release com
bugs?
oParece que o trabalho dos testadores falhou ao não encontrar os erros
não é?
oParece que algumas partes do código foram esquecidas pelos
desenvolvedores e testadores
rodrigo@ic.ufal.br 4
5. Cobertura
o Iremos ver algumas técnicas que ajudam a identificar o quanto
executamos do nosso código fonte sob teste
o Cuidado
“Our results suggest that coverage, while useful for
identifying under-tested parts of a program, should
not be used as a quality target because it is not a
good indicator of test suite efectiveness.”
Inozemtseva, Laura, and Reid Holmes. "Coverage Is Not
Strongly Correlated With Test Suite Effectiveness.“, ICSE 2014
http://www.linozemtseva.com/research/2014/icse/coverage/coverage_paper.pdf
rodrigo@ic.ufal.br 5
6. Quanto teste é suficiente?
o A gente começa a testar, gasta um bom tempo e se sente
confiante que fez um bom trabalho
rodrigo@ic.ufal.br 6
7. Mas ...
o De repente alguma coisa esquisita acontece e o nosso software
falha!
o Na prática, esquecemos de testar alguma parte do nosso
domínio da entrada
rodrigo@ic.ufal.br 7
8. Ideia
o A ideia é termos algumas métricas que nos digam, por exemplo:
oVocê está indo bem, seu score de cobertura é 14/100
oOu ainda:
o Você não executou a linhas 35, 70 e 195 da sua classe Queue
rodrigo@ic.ufal.br 8
9. Voltando um pouco para discutir a partição do
domínio
o Não é viável testar com todas as possíveis entradas
Domínio da entrada Contra-domínio (saídas)
rodrigo@ic.ufal.br 9
10. Suponha ainda
o Mesmo que você abstraia e considere classes do seu domínio
de entrada
o Suponha também que você tem acesso ao:
oCódigo do software que você irá testar
oEspecificações
oE tudo o mais que você precise para criar as melhores partições
possíveis do seu domínio da entrada
rodrigo@ic.ufal.br 10
11. Logo ...
o Você pega um ponto da partição, testa, analisa o resultado obtido e
se for igual ao esperado, ok! O sistema se comportou corretamente
o Mas em alguns casos, o sistema irá falhar, mesmo para pontos
diferentes dentro de uma mesma partição
o Ou seja ... Descobrimos uma outra partição dentro da partição que a gente
achava que era a melhor
o ... E culpamos a escolha da partição
o Só que esse processo vira um loop ... É difícil encontrar boas
partições ... E pior ainda é difícil medir (cobertura do domínio ???)
rodrigo@ic.ufal.br 11
12. Cobertura
o Na prática, a gente faz um pouco diferente e acaba
particionando também o domínio ... mas como consequência
o Mais fácil com exemplo ... Próximo slide
rodrigo@ic.ufal.br 12
13. Cobertura de funções
o Você terá 100% de cobertura de funções se todas as funções do
seu sistema forem executadas durante os testes
o Por exemplo, você pode fazer um teste que executa, por
exemplo, 181 das 250 funções do seu código
o Essa métrica 181/250 é uma das métricas de cobertura
rodrigo@ic.ufal.br 13
14. Ou seja,
o Você teve que escolher elementos do seu domínio que
exercitassem as funções do seu código
o As funções geraram saídas (contra-domínio)
o Ou seja, ao tentar cobrir as funções, você cobriu uma parte do
domínio e do contra-domínio de valores
oMas o foco foi na cobertura das funções
oE não em tentar cobrir todo o domínio
rodrigo@ic.ufal.br 14
15. Existem várias formas de medir a cobertura
o Cobertura de função
o Cobertura de comandos
o Cobertura de linhas
o Cobertura de ramos
o Cobertura de loops
o Cobertura Modified Condition/Decision Condition
rodrigo@ic.ufal.br 15
16. Iremos explorar cada uma delas ...
o ... mas primeiro ...
o... Um exemplo
o Uma árvore de busca binária
rodrigo@ic.ufal.br 16
19. delete (key)
o 3 casos
oRemovendo uma folha
rodrigo@ic.ufal.br 19
20. delete (key)
o 3 casos
oNó com um filho
rodrigo@ic.ufal.br 20
21. delete (key)
o 3 casos
oNó com 2 filhos
rodrigo@ic.ufal.br 21
22. Lets code it
o Não esqueçam de
fazer os testes
unitários enquanto
codificam
rodrigo@ic.ufal.br 22
23. Agora vamos incrementar um pouco
o Uma splay tree (com algumas simplificações)
oÁrvore de busca binária
oAuto ajustável
oElementos mais acessados são acessados mais rápidos
o Eles sobem para o topo da árvore
rodrigo@ic.ufal.br 23
24. Ideia
o Combinar as operações normais (insert e find) com uma nova
operação
oSplay
o Responsável por levar para o topo da árvore o elemento inserido ou buscado
o Ela faz uso da rotação de árvores
rodrigo@ic.ufal.br 24
25. Como rotacionar uma árvore?
o Mudar a estrutura da árvore sem interferir na ordem dos
elementos
rodrigo@ic.ufal.br 25
26. Consequências da rotação
o Você só poderá rotacionar p se ele
tiver um pai
o Se P já é filho esquerdo de Q, não
dá pra rodar pra esquerda, por
exemplo
o Se Q tiver um pai, ele precisará ser
atualizado para apontar para P e P
para ser filho ele
rodrigo@ic.ufal.br 26
27. Primeira tarefa
o Implementar
oright_rotate(self, node)
oleft_rotate(self, node)
rodrigo@ic.ufal.br 27
28. O splay (simplificado)
o Iremos rotacionar o nó até ele chegar na raiz
o Por exemplo:
28
8
4 9
3 6
5 7
right 8
left 5
4 9
3 5
7
6
8
5 9
4
7
6
3
4 8
3
7
6
right
9
30. Cobertura dos testes que você fez
o Vamos dar uma olhada na cobertura dos testes que você fez
o Para isso, iremos usar uma ferramenta do Python
o O Python Coverage irá contar quantos comandos foram
executados em relação ao total
o Cobertura de comandos
rodrigo@ic.ufal.br 30
31. Python coverage
(http://nedbatchelder.com/code/coverage/)
o pip install coverage
o Verifique se a pasta Script dentro do python está no seu path, se não estiver coloque. Por exemplo, no meu
computador essa pasta é: D:python3.3Scripts
o Vá para o diretório que você fez o caso de teste
o coverage run my_tests.py
o Troque my_tests.py pelo nome do seu script de testes
o coverage html
o Ele vai gerar um diretório chamado htmlcov
o Abra o arquivo index.html para ver os resultados
o Apagar resultados anteriores: coverage erase
o Resultado em outro formato: coverage report -m
rodrigo@ic.ufal.br 31
32. Rodou os testes instrumentados com a ferramenta de
cobertura?
o Provavelmente a cobertura não deu 100%
o Espere .... não codifique mais testes para obter
os 100% ainda
o Identifique por que os comandos não foram
executados?
o Era um código que você julgou que não precisava
ser testado?
o Você não conseguiu pensar nessa situação?
o Ué ... ele deveria ter executado esse comando
rodrigo@ic.ufal.br 32
33. O que ele nos diz?
o O teste de cobertura nos diz o que não testamos
o Ele deve sempre gerar uma reflexão da causa do
“esquecimento”
oNão saia tentando obter 100% de cobertura sem fazer essa reflexão
rodrigo@ic.ufal.br 33
34. Melhore os seus testes
o Se você julgou que esqueceu de testar algumas situações
importantes
o Melhore os seus casos de teste
rodrigo@ic.ufal.br 34
35. 100%
o Você obteve 100% de cobertura de
comandos
o Logo seu código está livre de bugs,
certo?
oClaro que não
oAinda podem existir muitos membros
do seu domínio de teste que podem
disparar um bug
rodrigo@ic.ufal.br 35
36. Exemplo
rodrigo@ic.ufal.br 36
import math
def is_prime(number):
if number <= 1 or (number % 2) == 0:
return False
for check in range(3, int(math.sqrt(number))):
if number % check == 0:
return False
return True
37. Testes
import unittest
from prime import is_prime
class MyTestCase(unittest.TestCase):
def test_is_prime(self):
self.assertFalse(is_prime(1))
self.assertFalse(is_prime(2))
self.assertTrue(is_prime(3))
self.assertFalse(is_prime(4))
self.assertTrue(is_prime(5))
self.assertFalse(is_prime(20))
self.assertFalse(is_prime(21))
self.assertFalse(is_prime(22))
self.assertTrue(is_prime(23))
self.assertFalse(is_prime(24))
rodrigo@ic.ufal.br 37
38. Rodando a cobertura
o coverage run test_prime.py
o coverage html
rodrigo@ic.ufal.br 38
39. Porém ...
o A nossa função possui uma falta
o Tente identificá-la
o Quando descobrir, modifique o
caso de teste para que a falta
seja exercitada e se transforme
em uma falha, que será “pega”
pelo seu caso de teste
o Só depois, corrija a falta
rodrigo@ic.ufal.br 39
40. O teste que irá exercitar a falta
import unittest
from prime import is_prime
class MyTestCase(unittest.TestCase):
def test_is_prime(self):
self.assertFalse(is_prime(9))
self.assertFalse(is_prime(25))
rodrigo@ic.ufal.br 40
41. A falta
o for check in range(3, int(math.sqrt(number))):
o Deveria ser:
o for check in range(3, int(math.sqrt(number))+1):
o Na função range, o primeiro parâmetro é inclusivo e o segundo
exclusivo. Ou seja, se vc a chamar range(1,4), ele irá gerar o
range: 1,2,3
rodrigo@ic.ufal.br 41
42. Mas o que aconteceu?
o Tínhamos 100% de cobertura de comandos e ainda assim
encontramos uma falta ?!
o A cobertura de comandos ainda deixa passar várias situações
oO comando pode executar mas retorna um valor errado
oO loop pode executar, mas executa um número errado de iterações
o...
rodrigo@ic.ufal.br 42
43. Possíveis conclusões sobre esse processo
o O fato de ter 100% cobertura de comandos não significa que o
software está livre de faltas
oSignifica apenas que ele executou todos os comandos
o Quando deixamos de cobrir algum comando, o que realmente
isso significa?
oQue temos que escrever um casos de teste para executar esse
comando?
rodrigo@ic.ufal.br 43
44. Possíveis conclusões
o Uma conclusão melhor seria
oSignifica que a gente não pensou no problema direito
oÉ melhor que a gente investigue porque que você não pensou naquele
caso do que simplesmente sair escrevendo o casos de teste para
executar o comando que foi deixado de lado
rodrigo@ic.ufal.br 44
46. Quantas são?
o Em [1], foram descritas 101 maneiras diferentes de medir a
cobertura
o Mas vamos simplificar e falar apenas de 6 delas, consideradas
as principais
[1] Kaner, Cem. "Software negligence and testing coverage." Proceedings of STAR 96 (1996): 313.
rodrigo@ic.ufal.br 46
47. Cobertura de comandos
o Já vimos essa métrica através da ferramenta Python Coverage
o Vamos só detalhar um pouco mais
o Suponha:
rodrigo@ic.ufal.br 47
if x == 0:
y += 1
if y == 0:
x += 1
Se chamarmos com:
(x= 0, y= -1)
obteremos 100% dos comandos executados
(x=20, y=20)
2/4 executados, ou seja, 50%
48. Cobertura de linhas
o Muito parecido com a cobertura de comandos
o Mas conta as linhas ao invés de comandos
o Logo, se o seu código tiver um comando por linha, as métricas
serão iguais
rodrigo@ic.ufal.br 48
49. Cobertura de linhas
o Código em C:
int do_something(int a, int b)
{
int c;
if (a>b) c=a;else c=b; printf("%dn",c);
o Independentemente dos valores de a e b obteremos 100% de
cobertura de linha, mesmo que nem todos os comandos
tenham sido executados
rodrigo@ic.ufal.br 49
}
50. Quiz
1. Baixe esse código: http://goo.gl/M07GMb
2. Escreva um teste unitário
class MyTestCase(unittest.TestCase):
def test_stats(self):
l = [31]
my_map = stats(l)
self.assertEqual(31,my_map["min"])
self.assertEqual(31,my_map["max"])
self.assertEqual(31,my_map["median"])
self.assertEqual([31],my_map["modes"])
3. Modifique o teste unitário para obter 100%
de cobertura de comandos
rodrigo@ic.ufal.br 50
51. Quiz (continuação)
4. Insira uma falta na função “stats” de forma que a falta passe
desapercebida pelo teste que você tinha escrito
5. Escreva outro teste que capture a falta que você inseriu
rodrigo@ic.ufal.br 51
52. Uma possível solução
o Introdução da falta
oColocar um valor absoluto, assim irá ignorar os valores negativos
oEssa falta não será detectada pelo teste já feito
oVeja a linha 6:
https://gist.github.com/r0drigopaes/401b298741c2fa88f70a
o Testes para pegar a falta
oVeja a linha 32:
https://gist.github.com/r0drigopaes/be13f8557dd604b57b01
rodrigo@ic.ufal.br 52
53. Cobertura de ramos
o É a métrica que se preocupa com os ramos da execução do seu
código
o Por exemplo, para obter 100% no ramo ...
if (x == 0):
y = y +1
o ... ele precisaria ser executado em ambas as possibilidades
oCom x igual a 0 e com x diferente de 0
rodrigo@ic.ufal.br 53
54. Cobertura de ramos
def foo(x,y):
if x == 0:
y += 1
if y == 0:
x += 1
54
X == 0
Y == 0
Y += 1
X+=1
... 4 ramos no total
55. Cobertura de ramos (python)
o coverage run –branch seuarquivo.py
o coverage html
def foo(x,y):
if x == 0:
y += 1
if y == 0:
x +=1
foo(0,1)
rodrigo@ic.ufal.br 55
56. Como o coverage calcula?
o coverage=execuções reais(er)/oportunidades de execução(oe)
o oe = statements + branches
o er = oe – (missing + partial)
o Exemplo:
o oe = 7 + 4 = 11 :: er = 11 – (2 + 2) = 7 :: logo
o Coverage = 7/11 = 64%
def foo(x,y):
if x == 0:
y += 1
if y == 0:
x +=1
foo(0,1)
rodrigo@ic.ufal.br 56
57. Ainda sobre o cálculo
o oe = 8 + 4 = 12
o er = 12 – (3+2) =7
o Coverage = 7/12 = 58%
def foo(x,y):
if x == 0:
y += 1
x += 2
if y == 0:
x +=1
foo(0,1)
rodrigo@ic.ufal.br 57
58. Informações úteis
o Número da linha que não
foi executada no ramo
oNesse caso, o primeiro if
nunca foi verdadeiro, pois não
“pulou” para a linha 5
o E o segundo também não,
pois não pulou para a linha 8
rodrigo@ic.ufal.br 58
59. Cobertura de loops
o Conta se o “corpo” de um loop foi executado pelo menos
o0 vezes
o1 vez
oMais de uma vez
o A forma específica de contagem pode variar
oO coverage não conta essa métrica
rodrigo@ic.ufal.br 59
60. Cobertura de loops
for loop in open("file"):
process(line)
o Para obter cobertura complete de loop:
oArquivo sem nenhuma linha
oArquivo com uma linha
oArquivo com pelo menos 2 linhas
rodrigo@ic.ufal.br 60
61. Complexidade Ciclomática
o Ideia: medir a quantidade de decisões no código-fonte
oQuanto menos decisões, mais simples de manter
oTambém traz a noção de caminhos básicos independentes
Thomas J. Mccabe; A Complexity Measure. IEEE
Transactions on Software Engineering, 1976
http://dx.doi.org/10.1109/TSE.1976.233837
rodrigo@ic.ufal.br 61
62. Complexidade Ciclomática
o Ver o programa como um grafo
o Onde
oe : arestas
on: nós
op: componentes conectados
rodrigo@ic.ufal.br 62
66. Teste baseado na complexidade ciclomática
o Basis Path
o Mas vamos explicar com um exemplo ...
rodrigo@ic.ufal.br 66
67. Euclides
euclid(int m, int n)
{
int r;
if(n>m){
r = m;
m = n;
n = r;
}
r = m % n;
while (r!=0){
m = n;
n = r;
r = m % n;
}
return n;
6
7
8
9
10
11
12
2
3
} rodrigo@ic.ufal.br 67
0
1
2
3
4
5
6
7
8
9
10
11
12
13
0
1
5
13
4
V = 15 – 14 + 2
V = 3
68. Euclides
euclid(int m, int n)
{
int r;
if(n>m){
r = m;
m = n;
n = r;
}
r = m % n;
while (r!=0){
m = n;
n = r;
r = m % n;
}
return n;
6
7
8
9
10
11
12
2
3
} rodrigo@ic.ufal.br 68
0
1
2
3
4
5
6
7
8
9
10
11
12
13
0
1
5
13
4
69. Euclides
o Qualquer caminho
pode ser expresso
como uma combinação
linear de um “basis
path”
o Exemplo:
o0 1 2 3 4 5 6 7 8 9 10 7 8
9 10 11 12 13
o= B2 – 2*B1 + 2*B3
0
1
5
6
7
8
9
10
11
12
13
2
3
4
rodrigo@ic.ufal.br 69
70. o [Mostrar as operações algébricas com matrizes]
rodrigo@ic.ufal.br 70
71. MC/DC
o Modified Condition Decision Coverage
o Essa é mais fácil mostrando um exemplo:
oif a or (b and c):
print(“It is true!!”)
oOu seja, a gente vai imprimir se a for verdade ou então b ou c
rodrigo@ic.ufal.br 71
72. MC/DC
Passo 1: em cada condição usada na decisão, procurar por aquelas que afetam a saída de forma independente
A B C A or (B and C)
True True True True
True True False True
True False True True
True False False True
False True True True
False True False False
False False True False
False False False False
a) Nesse caso, “fixe B e C” e mude o
valor de A.
b) Ele altera a saída? Se sim, esses
dois seriam 2 casos de testes
a) T, T, T e F, T, T
rodrigo@ic.ufal.br 72
73. MC/DC
Passo 1: em cada condição usada na decisão, procurar por aquelas que afetam a saída de forma independente
A B C A or (B and C)
True True True True
True True False True
True False True True
True False False True
False True True True
False True False False
False False True False
False False False False
a) Agora vamos tentar com B. Fixe
A (True) e C(True) e varie B.
b) Afetou a saída? Não. Tente outra
possibilidade
a) A(False), B(True), C(False)
c) Altere somente B, de novo
a) A(False), B(False), C(False)
d) Alterou?
a) Sim
b) F, T, F e F, F, F
rodrigo@ic.ufal.br 73
74. MC/DC
A B C A or (B and C)
True True True True
True True False True
True False True True
True False False True
False True True True
False True False False
False False True False
False False False False
rodrigo@ic.ufal.br 74
A mesma coisa para C
a) A(False), B(True), C(True)
b) Altere para
a) A(False), B(True), C(False)
c) F, T,T e F, T, F
75. MC/DC
o Teríamos os seguintes casos de teste:
oT, T, T e F, T, T
oF, T, F e F, F, F
oF, T,T e F, T, F
oT, T, T e F, T, T
oF, F, F
rodrigo@ic.ufal.br 75
76. MC/DC
o Usado em partes específicas de sistemas críticos
o Não conheço nenhuma ferramenta para python
rodrigo@ic.ufal.br 76