Testes de Software - Módulo 2

Post on 11-Jun-2015

520 views 1 download

description

Fala principalmente sobre a cobertura de testes

Transcript of Testes de Software - Módulo 2

Testes de Software

Prof. Rodrigo de Barros Paes

rodrigo@ic.ufal.br

rodrigo@ic.ufal.br 2

Cobertura de testes

rodrigo@ic.ufal.br 3

Ubuntu release

oUbuntu 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 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 5

Cobertura

o Iremos ver algumas técnicas que ajudam a identificar o quanto executamos do nosso código fonte sob teste

oCuidado

http://www.linozemtseva.com/research/2014/icse/coverage/coverage_paper.pdf

“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

rodrigo@ic.ufal.br 6

Quanto teste é suficiente?

oA gente começa a testar, gasta um bom tempo e se sente confiante que fez um bom trabalho

rodrigo@ic.ufal.br 7

Mas ...

oDe repente alguma coisa esquisita acontece e o nosso software falha!

oNa prática, esquecemos de testar alguma parte do nosso domínio da entrada

rodrigo@ic.ufal.br 8

Ideia

oA 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 9

Voltando um pouco para discutir a partição do domínio

oNão é viável testar com todas as possíveis entradas

Domínio da entrada Contra-domínio (saídas)

rodrigo@ic.ufal.br 10

Suponha ainda

oMesmo 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 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

oOu 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 12

Cobertura

oNa prática, a gente faz um pouco diferente e acaba particionando também o domínio ... mas como consequência

oMais fácil com exemplo ... Próximo slide

rodrigo@ic.ufal.br 13

Cobertura de funções

oVocê 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 14

Ou seja,

oVocê teve que escolher elementos do seu domínio que exercitassem as funções do seu código

oAs funções geraram saídas (contra-domínio)

oOu 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 15

Existem várias formas de medir a cobertura

oCobertura de função

oCobertura de comandos

oCobertura de linhas

oCobertura de ramos

oCobertura de loops

oCobertura Modified Condition/Decision Condition

rodrigo@ic.ufal.br 16

Iremos explorar cada uma delas ...

o ... mas primeiro ...

o ... Um exemplo

o Uma árvore de busca binária

rodrigo@ic.ufal.br 17

Operações

o insert (key)

rodrigo@ic.ufal.br 18

find (key)

rodrigo@ic.ufal.br 19

delete (key)

o 3 casos

oRemovendo uma folha

rodrigo@ic.ufal.br 20

delete (key)

o 3 casos

oNó com um filho

rodrigo@ic.ufal.br 21

delete (key)

o 3 casos

oNó com 2 filhos

rodrigo@ic.ufal.br 22

Lets code it

oNão esqueçam de fazer os testes unitários enquanto codificam

rodrigo@ic.ufal.br 23

Agora vamos incrementar um pouco

oUma 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 24

Ideia

oCombinar 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 25

Como rotacionar uma árvore?

oMudar a estrutura da árvore sem interferir na ordem dos elementos

rodrigo@ic.ufal.br 26

Consequências da rotação

oVocê 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 27

Primeira tarefa

o Implementar

o right_rotate(self, node)

o left_rotate(self, node)

28

O splay (simplificado)

o Iremos rotacionar o nó até ele chegar na raiz

o Por exemplo:

8

4 9

63

5 7

8

4 9

53

7

6

8

5 9

4

7

6

3

leftright 5

4 8

3

7

6

right

9

rodrigo@ic.ufal.br 29

Escreva os seus testes

rodrigo@ic.ufal.br 30

Cobertura dos testes que você fez

oVamos dar uma olhada na cobertura dos testes que você fez

o Para isso, iremos usar uma ferramenta do Python

oO Python Coverage irá contar quantos comandos foram executados em relação ao total

oCobertura de comandos

rodrigo@ic.ufal.br 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.3\Scripts

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 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?

oUé ... ele deveria ter executado esse comando

rodrigo@ic.ufal.br 33

O que ele nos diz?

oO 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 34

Melhore os seus testes

o Se você julgou que esqueceu de testar algumas situações importantes

oMelhore os seus casos de teste

rodrigo@ic.ufal.br 35

100%

oVocê 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 36

Exemplo

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

rodrigo@ic.ufal.br 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 38

Rodando a cobertura

o coverage run test_prime.py

o coverage html

rodrigo@ic.ufal.br 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 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 41

A falta

o for check in range(3, int(math.sqrt(number))):

oDeveria ser:

o for check in range(3, int(math.sqrt(number))+1):

oNa 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 42

Mas o que aconteceu?

o Tínhamos 100% de cobertura de comandos e ainda assim encontramos uma falta ?!

oA 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 43

Possíveis conclusões sobre esse processo

oO 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

oQuando 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 44

Possíveis conclusões

oUma 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 45

Métricas de cobertura

rodrigo@ic.ufal.br 46

Quantas são?

o Em [1], foram descritas 101 maneiras diferentes de medir a cobertura

oMas 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 47

Cobertura de comandos

o Já vimos essa métrica através da ferramenta Python Coverage

oVamos só detalhar um pouco mais

o Suponha:if x == 0: y += 1if 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%

rodrigo@ic.ufal.br 48

Cobertura de linhas

oMuito parecido com a cobertura de comandos

oMas 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 49

Cobertura de linhas

oCódigo em C:

o Independentemente dos valores de a e b obteremos 100% de cobertura de linha, mesmo que nem todos os comandos tenham sido executados

int do_something(int a, int b){ int c; if (a>b) c=a;else c=b; printf("%d\n",c);}

rodrigo@ic.ufal.br 50

Quiz

1. Baixe esse código: http://goo.gl/M07GMb

2. Escreva um teste unitárioclass 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 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 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 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

54

Cobertura de ramos

def foo(x,y):

if x == 0:

y += 1

if y == 0:

x += 1

X == 0

Y == 0

Y += 1

X+=1

...4 ramos no total

foo(0,1) ?

foo(0,-1) ?

rodrigo@ic.ufal.br 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 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 57

Ainda sobre o cálculo

o oe = 8 + 4 = 12

o er = 12 – (3+2) =7

oCoverage = 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 58

Informações úteis

oNú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

oE o segundo também não, pois não pulou para a linha 8

rodrigo@ic.ufal.br 59

Cobertura de loops

oConta se o “corpo” de um loop foi executado pelo menos

o0 vezes

o1 vez

oMais de uma vez

oA forma específica de contagem pode variar

oO coverage não conta essa métrica

rodrigo@ic.ufal.br 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 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 62

Complexidade Ciclomática

oVer o programa como um grafo

oOnde

oe : arestas

on: nós

op: componentes conectados

rodrigo@ic.ufal.br 63

Complexidade ciclomática

o Sequência

oV = 1 – 2 + 2

oV = 1

A = 5+3;B = A+1;

1 caminho

rodrigo@ic.ufal.br 64

Complexidade ciclomática

oDecisão

oV = 4 – 4 + 2

oV = 2

Com uma decisão, aumentamos um na complexidade

if (a>b){ printf(“x”);}else{ printf(“y”);}b = a+b;

2 caminhos

rodrigo@ic.ufal.br 65

Complexidade ciclomática

oDecisão

oV = 12 – 10 +2

oV = 4

3 decisões.

4 caminhos

rodrigo@ic.ufal.br 66

Teste baseado na complexidade ciclomática

oBasis Path

oMas vamos explicar com um exemplo ...

rodrigo@ic.ufal.br 67

Euclideseuclid(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;}

012345678910111213

0

1

5

13

12

11

10

9

8

7

6

4

3

2

V = 15 – 14 + 2V = 3

rodrigo@ic.ufal.br 68

Euclideseuclid(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;}

012345678910111213

0

1

5

13

12

11

10

9

8

7

6

4

3

2

rodrigo@ic.ufal.br 69

Euclides

oQualquer 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

13

12

11

10

9

8

7

6

4

3

2

rodrigo@ic.ufal.br 70

o [Mostrar as operações algébricas com matrizes]

rodrigo@ic.ufal.br 71

MC/DC

oModified Condition Decision Coverage

o Essa é mais fácil mostrando um exemplo:

o if 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 72

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

Passo 1: em cada condição usada na decisão, procurar por aquelas que afetam a saída de forma independente

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 testesa) T, T, T e F, T, T

rodrigo@ic.ufal.br 73

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

Passo 1: em cada condição usada na decisão, procurar por aquelas que afetam a saída de forma independente

a) Agora vamos tentar com B. Fixe A (True) e C(True) e varie B.

b) Afetou a saída? Não. Tente outra possibilidadea) A(False), B(True),

C(False)c) Altere somente B, de novo

a) A(False), B(False), C(False)

d) Alterou?a) Simb) F, T, F e F, F, F

rodrigo@ic.ufal.br 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

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

rodrigo@ic.ufal.br 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

3 casos de teste cobririam 100% mc/dc

rodrigo@ic.ufal.br 76

MC/DC

oUsado em partes específicas de sistemas críticos

oNão conheço nenhuma ferramenta para python