Vous êtes sur la page 1sur 67

Mestrado em Engenharia Informtica

Testes de Programas em Haskell


Teste e Qualidade de Software

Pedro Rodrigo Caetano Strecht Ribeiro


Junho 2005

Testes de Programas em Haskell

Teste e Qualidade de Software

Sumrio
1 Introduo 2 Breve introduo linguagem Haskell
2.1 2.2 2.3 2.4 O paradigma funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A linguagem Haskell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6 7
7 8 10 12

Construes e estruturas de dados

Paradigma imperativo ou funcional?

3 Aplicao de simplicao e derivao de expresses matemticas


3.1 3.2 3.3 3.4 Objectivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Gramtica das expresses Arquitectura da aplicao

13
13 13 15 16

Blocos funcionais da aplicao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4 Framework de testes HUnit 1.0


4.1 4.2 4.3 4.4 4.5 4.6 4.7 Asseres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Casos de teste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Agrupamento de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Contagem de casos de teste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18
18 21 22 23 25 27 32

Caminhos na hierarquia de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Execuo de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Funcionalidades avanadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5 Arquitectura do ambiente de testes


5.1 5.2 5.3 5.4 5.5 5.6 5.7 Componentes da arquitectura do ambiente de testes . . . . . . . . . . . . . . . . . . . .

35
35 36 36 36 36 37 38

Framework

HUnit

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Aplicao a testar

Testador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ficheiro de testes e dialecto HtestML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ficheiro de resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6 Concepo dos casos de teste


6.1 6.2 Abordagem para a concepo dos casos de teste . . . . . . . . . . . . . . . . . . . . . . . Regras de especicao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40
40 40

Testes de Programas em Haskell

Teste e Qualidade de Software

6.2.1 6.2.2 6.2.3 6.3

Converso de formatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simplicao de Expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Derivao de Expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41 43 44 45 46 49 53

Casos de Teste 6.3.1 6.3.2 6.3.3

Converso de formatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simplicao de Expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Derivao de Expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 Execuo dos testes e anlise dos resultados


7.1 7.2 Execuo dos testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anlise dos resultados 7.2.1 7.2.2 7.2.3

58
58 60 60 61 63

Converso de formatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simplicao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Derivao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

8 Concluso 9 Referncias

65 66

Testes de Programas em Haskell

Teste e Qualidade de Software

Lista de Figuras
3.1 3.2 4.1 4.2 4.3 5.1 Gramtica da aplicao representada em EBNF . . . . . . . . . . . . . . . . . . . . . . . Arquitectura da aplicao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 15 23 24 26 35

Suite de testes de simplicao

Variante suite de testes de simplicao

Suite de testes de simplicao com numerao . . . . . . . . . . . . . . . . . . . . . . . Arquitectura do ambiente de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Testes de Programas em Haskell

Teste e Qualidade de Software

Lista de Tabelas
3.1 4.1 4.2 4.3 4.4 4.5 4.6 4.7 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 Exemplos de expresses matemticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Contagem de casos de teste da suite de testes . . . . . . . . . . . . . . . . . . . . . . . . Contagem de casos de teste da variante da suite de testes . . . . . . . . . . . . . . . . . 14 24 24 26 32 32 33 34 41 41 42 42 43 43 44 44 45 46 47 47 48 48

Caminhos na hierarquia de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Operadores de construo de asseres . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemplos de construes de asseres com operadores . . . . . . . . . . . . . . . . . . .

Operadores de construo de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemplos de construes de testes com operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Transformao de expresses para o formato interno

Vericaes efectuadas para validao sintctica da expresso . . . . . . . . . . . . . . . Transformao de expresses para o formato externo . . . . . . . . . . . . . . . . . . . . Construo da representao em rvore de uma expresso Operaes algbricas bsicas tratadas pela aplicao . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

Propriedades dos operadores algbricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . Funes matemticas tratadas pela aplicao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Vericaes efectuadas para validao semntica Regras de derivao de expresses

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6.10 Testes de integridade de valores numricos inteiros

6.11 Testes de converso de formato externo para o formato interno

6.12 Testes de converso de validao sintctica . . . . . . . . . . . . . . . . . . . . . . . . . . 6.13 Testes de converso de formato interno para o formato externo . . . . . . . . . . . . . .

6.14 Testes bsicos de converso de expresses no formato interno a representao em rvore

6.15 Testes genricos de converso de expresses no formato interno a representao em rvore 49 6.16 Testes de operaes algbricas bsicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 50 51 51 52 52 53 53 54

6.17 Testes das propriedades dos operadores algbricos . . . . . . . . . . . . . . . . . . . . . . 6.18 Testes das propriedades dos operadores algbricos . . . . . . . . . . . . . . . . . . . . . . 6.19 Testes de simplicao de avaliao de funes 6.20 Testes de simplicao de avaliao de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6.21 Testes de validao semntica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.22 Testes de somas simplicveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.23 Testes de somas no simplicveis 6.24 Testes de diferenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Testes de Programas em Haskell

Teste e Qualidade de Software

6.25 Testes de produtos simplicveis

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54 55 55 55 55 56 57 58 60 61 61 61 62 63

6.26 Testes de produtos no simplicveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.27 Testes de divises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.28 Testes de potncias simplicveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.29 Testes de potncias no simplicveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.30 Testes de derivao de expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.31 Testes de composio de regras de derivao . . . . . . . . . . . . . . . . . . . . . . . . . 7.1 7.2 7.3 7.4 7.5 7.6 7.7 Execuo de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Resultados quantitativos da execuo de testes

Falhas da converso de formato interno para formato externo

Falhas da vericao de operaes bsicas e suas propriedades . . . . . . . . . . . . . . . Falhas da converso de avaliao de funes . . . . . . . . . . . . . . . . . . . . . . . . . Falhas na qualidade da simplicao de expresses . . . . . . . . . . . . . . . . . . . . .

Falhas no processo de derivao de expresses . . . . . . . . . . . . . . . . . . . . . . . .

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 1

Introduo
Este relatrio apresenta o resultado nal do estudo e desenvolvimento de uma arquitectura de testes de programas escritos em linguagem Haskell, no mbito do projecto da disciplina de Teste e Qualidade de Software da edio de 2004/2005 do Mestrado em Engenharia Informtica da Faculdade de Engenharia da Universidade do Porto. A arquitectura implementada visa fornecer uma plataforma para testar programas em Haskell, utilizando como base a

framework

HUnit 1.0.

Como exemplo de aplicao em teste utilizou-se uma

aplicao desenvolvida na mesma linguagem. O segundo captulo apresenta a linguagem Haskell enquadrado-a no paradigma da programao funcional e comparando-a com linguagens imperativas como o C. So enumerados os potenciais benefcios da linguagem e apresenta-se uma panormica geral das suas construes e estruturas de dados. O captulo conclui com uma breve discusso sobre os dois paradigmas de programao em causa: o imperativo e o funcional. O terceiro captulo apresenta a aplicao que servir de base aos testes, a Aplicao de Simplicao e Derivao de Expresses Matemticas, desenvolvida em Haskell. Descreve-se o objectivo da aplicao, a sua arquitectura e blocos funcionais. O quarto captulo efectua um estudo da

framework

HUnit 1.0, que serve de base arquitectura de

testes desenvolvida. So abordados os conceitos de asseres, testes e casos de teste posicionado-os no contexto da

framework.

So aplicadas as suas principais funcionalidades de contagem de casos de teste,

identicao de caminhos em hierarquias de testes, execuo de testes e outras mais avanadas. O quinto captulo descreve os componentes da arquitectura do ambiente de testes. Estes componentes incluem a

framework

HUnit 1.0, a aplicao a testar, a execuo de testes e a interface. tambm

apresentado um dialecto XML de descrio de testes unitrios em Haskell, denominado HtestML. O sexto captulo aborda todo o processo de concepo de casos de teste. So enunciadas as regras de especicao da aplicao em teste e organizados os casos de testes que as vericam. Esses casos de teste so classicados em trs grandes categorias: converso de formatos entre expresses, simplicao de expresses e clculo de derivadas. O stimo captulo descreve a execuo dos testes e analisa os resultados obtidos. So identicados os casos de teste que acusam falhas na aplicao e discutida a sua gravidade e impacto na aplicao. Encerra-se o relatrio com uma concluso que discute os objectivos atingidos com o trabalho.

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 2

Breve introduo linguagem Haskell


Neste captulo introduz-se a linguagem em que a arquitectura de testes e o sistema a ser testado foram desenvolvidos  a linguagem Haskell. O objectivo enquadrar a linguagem no contexto dos So abordadas tambm paradigmas de programao e descrever as suas principais caractersticas. algumas construes e estruturas de dados da linguagem.

2.1 O paradigma funcional


C, Java, Pascal, Ada, entre outras so linguagens imperativas, algumas incluindo orientao por objectos. So imperativas no sentido em que consistem numa sequncia de comandos que so executados uns aps os outros. Um programa funcional pode consistir numa uma expresso simples, que ao ser executado avalia essa expresso. Um exemplo simples de programao funcional a utilizao de uma folha de clculo. O valor

de uma clula pode ser exprimido em funo dos valores de outras clulas. O foco sempre naquilo que est a ser calculado e no na forma como deve ser calculado. No indicada a ordem pela qual as clulas devem ser calculadas, essa responsabilidade deixada prpria folha de clculo. Tambm no so indicadas quaisquer tcnicas de gesto de memria, esperando-se, pelo contrrio, que a folha de clculo parea ser innita. Tudo o que indica o valor de uma clula atravs de uma expresso

(cujas componentes podem ser avaliadas por qualquer ordem), em vez de uma sequncia de comandos que calculem o ser valor. Uma consequncia de no haver ordem pr-estabelecida que a noo de

atribuio no muito til. Se no se conhece o momento em que uma atribuio ocorre, tal no pode ser incorporado na expresso. este aspecto que fomenta o maior contraste com linguagens como o C em que a sequncia de atribuies tem que ser cuidadosamente planeada. O facto do foco passar

do conceito de baixo nvel como para o de alto nvel o qu a caracterstica mais marcante que distingue as linguagens funcionais das imperativas. Outra linguagem quase-funcional a SQL para interrogao e manuteno de bases de dados. Uma interrogao SQL uma expresso que involve projeces, seleces, junes e condies. A expresso indica quais as relaes que devem ser interrogadas e o que se pretende, no entanto, no fornece qualquer indicao de como tal deve ser obtido. As implementaes de SQL incluem algoritmos de optimizao de interrogaes que tm como principal objectivo determinar qual a melhor ordem para avaliar a expresso. A execuo desses algoritmos transparente para o programador.

Testes de Programas em Haskell

Teste e Qualidade de Software

2.2 A linguagem Haskell


Haskell uma linguagem de programao criada em 1990 e enquadrada no paradigma da programao funcional. Outras exemplos de linguagens funcionais so Lisp, Scheme, Erlang, Clean, Mercury, ML, OCaml, SQL, XSL, etc. uma linguagem polimrca, altamente tipada, com modelo de avaliao

lazy

e considerada pura no contexto das linguagens funcionais. O seu nome presta homenagem a Haskell Brooks Curry, cujo trabalho matemtico serve de base s linguagens funcionais, nomeadamente no que respeita a

lambda calculus.
Os

A principal motivao para o aparecimento de linguagens funcionais como o Haskell, o de tornar o processo de escrita e manuteno de grandes sistemas de software mais simples e econmicos.

criadores da linguagem argumentam como vantagens de utilizao o aumento da produtividade dos programadores, a produo de cdigo mais curto, mais legvel e de manuteno mais simples. Ar-

gumentam tambm a diminuio de erros e maior abilidade e a reduo do fosso semntico entre o programador devido ao maior poder expressivo. A linguagem Haskell tem um espectro de aplicao alargado servindo para uma grande variedade de aplicaes. Segundo os seus autores, particularmente adequada para programas com grande necessidade de modicao e manuteno. A maior parte do ciclo de vida de um produto de software

corresponde especicao, desenho e manuteno e no propriamente programao. As linguagens funcionais so vocacionadas para escrever especicaes que podem ser executadas e consequentemente testadas. Essas especicaes constituem o primeiro prottipo do programa nal. Os programas nestas linguagens so relativamente simples de manter porque o cdigo mais curto, mais claro e o controlo rigoroso de efeitos laterais elimina uma grande quantidade de interaces imprevistas. Um exemplo tpico que pretende ilustrar estes conceitos a implementao do algoritmo de ordenao de um vector pelo mtodo

Quicksort, apresentado-se a codicao em Haskell e em C.

A implementao em Haskell pretende ser concisa e exprimir a inteno do desenho do mtodo:

qsort [] = [] qsort (x:xs) = qsort lt ++ [x] ++ qsort ge where lt = [y | y <- xs, y < x] ge = [y | y <- xs, y >= x]

A implementao em C mais densa e complexa:

qsort( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }

Testes de Programas em Haskell

Teste e Qualidade de Software

Este exemplo-limite frequentemente utilizado pelo entusiastas da linguagem Haskell para ilustrar o seu poder expressivo. Tendo este exemplo como base, so enumerados os seguintes benefcios da

linguagem Haskell e da programao funcional em geral: 1.

Conciso
Programas escritos em linguagem funcionais tendem a ser mais concisos do que os seus equivalentes em linguagens imperativas. Mesmo atendendo ao facto de que a implementao do algoritmo

quicksort
2.

constitui um caso extremo, de uma forma geral a reduo em linhas de cdigo pode

variar numa razo de 2 a 10.

Facilidade de compreenso
Segundo os seus autores, possvel compreender a implementao do

quicksort

sem qualquer

conhecimento prvio de Haskell. A primeira linha arma que o resultado de ordenar uma lista vazia uma lista vazia. A segunda linha arma que para ordenar uma lista cujo primeiro elemento

x e a parte restante xs, basta ordenar os elementos de xs que so inferiores a x, os elementos de xs que so iguais ou superiores a x e concatenar os resultados com x no meio. Como as sub-listas
resultantes so inferiores lista original o processo acaba por convergir para as sub-listas vazias. A implementao em C no de fcil compreenso. necessrio seguir o uxo de execuo e as variveis utilizadas, sendo tambm mais passvel de erros de programao.

3.

Forte sistema de tipos


A maioria das linguagens funcionais, e o Haskell em particular, so fortemente tipadas, eliminando uma grande quantidade de erros comuns durante a compilao. De uma forma geral um sistema de tipo permite que o programador indique

piori

como devem ser tratados os dados, associado-os

a um tipo. Com um forte sistema de tipos no existe, por exemplo, a possibilidade de tratar um inteiro como um apontador ou seguir um apontador nulo. 4.

Avaliao lazy
Muitas linguagens funcionais s avaliam as partes do programa que so necessrias para o clculo que efectuado. Designa-se a este tipo de avaliao por

lazy.

As estruturas de dados, como as

listas, so avaliadas s at onde for necessrio podendo haver partes delas que nem so avaliadas. 5.

Abstraco poderosa
As funes de ordem elevada so um mecanismo de abstraco que oferecido pelas linguagens funcionais. Consiste em poder usar funes como argumentos, parmetros de sada, armazenamento em estruturas de dados e qualquer outra operao que possa ser efectuada com valores de qualquer tipo de dados. A principal vantagem que a utilizao de funes de ordem elevada

pode aumentar bastante a estrutura e modularidade de muitos programas. 6.

Gesto automtica de memria


Muitos programas sosticados precisam de alocar memria dinamicamente na utilizam-se funes especcas (malloc) para alocar o espao e inicializ-lo.

heap.

Em C

O programador

tambm responsvel por libertar a rea alocada, caso contrrio ca sujeito ocorrncia de apontadores vazios. As linguagens funcionais libertam o programador destas tarefas e semelhana do Java possuem mecanismos de memria de forma automtica.

garbage collector

que se encarregam de assumir toda a gesto de

Testes de Programas em Haskell

Teste e Qualidade de Software

2.3 Construes e estruturas de dados


Nesta seco abordam-se de forma muito breve as principais construes e estruturas de dados da linguagem Haskell. As expresses simples incluem literais, operadores e aplicaes de funes:

0 5 (-1) 3.14159 'c' 7 + 9 abs (-4) sqrt 4.0


Embora seja possvel indicar tipos o operador inferncia de tipos. Os tipos primitivos so os seguintes:

::,

normalmente deixa-se que o compilador faa

Int

 Inteiro de preciso xa  Inteiro de preciso arbitrria

Integer Float

 Fraccionrio de preciso xa  Fraccionrio de preciso dupla

Double Char Bool

 Caracter Ascii  Valor booleano,

True

ou

False

Existem tambm tipos agregados:

Tuplos  Sequncia de elementos de tipos pr-existentes podendo ser diferentes uns dos outros. O nmero de elementos est xado na denio do tipo. Um exemplo o tipo que pode ser instanciado com o tuplo

(Int, Float, String), (42, 3.14159, "Hello, world!"). [1, 2, 3]

Listas  Sequncia ordenada de elementos de um tipo, sendo o nmero de elementos arbitrrio. Alguns exemplos so a lista vazia caracteres)

[],

uma lista de inteiros

e uma

string

(lista de

"abc".

Note-se que podem haver listas de tuplos ou mesmo listas de listas.

A linguagem tem construes

let,

como o exemplo seguinte:

let y = x + 2 x = 5 in x / y
A expresso

let

no se destina a permitir atribuies j que

no so variveis, tratam-se apenas

de identicadores para as expresses calculadas, que no podem ser re-utilizados.

10

Testes de Programas em Haskell

Teste e Qualidade de Software

A estrutura condicional bsica a

if-then-else,
then
e

encontrada nas linguagens imperativas. A principal tm que avaliar para um valor e tm que ser do

diferena que a expresso nos ramos mesmo tipo:

else

if a == b then "foo" else "bar"


A denio de uma funo pode ser acompanhada de uma assinatura que indica os tipos dos argumentos e do valor retornado. Um exemplo uma funo simples que some dois nmeros:

add :: Int -> Int -> Int add x y = x + y


A funo

add

tem dois argumentos de tipo

Int

e retorna um valor de tipo

Int.

A mesma funo pode ser denida com um nico parmetro, um tuplo par, que agregue os dois valores a somar:

add :: (Int, Int) -> Int add (x, y) = x + y


As funes podem ser assim denidas como um conjunto de equaes em que so tratados os vrios casos possveis de parmetros de entrada. Um exemplo a funo que soma todos os valores de uma lista de inteiros. A funo trata separadamente o caso excepcional (lista vazia) e o caso geral. Note-se a utilizao da recursividade, muito frequente em programas funcionais. O primeiro elemento da lista denotado por

e a parte restante (cauda da lista) denotada como a sub-lista

xs.

sum :: [Int] -> Int sum [] = 0 sum (x:xs) = x + sum xs


Uma construo particularmente til para detalhar diferentes comportamento dentro de uma funo so as denominadas

guardas

(denotadas pelo smbolo |), que permitem isolar os casos importantes em

que a funo altera o seu comportamento. Um exemplo a seguinte denio da funo

abs:

abs abs abs | |

:: Integer -> Integer 0 = 0 x x > 0 = x x < 0 = -x

Existem mais algumas construes para alm das apresentadas possibilitando um bom poder expressivo na formulao de algoritmos. tambm bastante rica em termos de bibliotecas de funes e

frameworks, estando continuamente em desenvolvimento novas extenses da linguagem. A partir do website da linguagem, http://www.haskell.org/, possvel ter acesso a inmeros tutoriais introdutrios bem como documentao extremamente aprofundada da linguagem. So disponibilizadas muitas bibliotecas que podem ser livremente importadas. Algumas dessas bibliotecas extendem bastante a linguagem dotando-a da possibilidade de poder rivalizar com muitas linguagens imperativas.

11

Testes de Programas em Haskell

Teste e Qualidade de Software

2.4 Paradigma imperativo ou funcional?


A implementao do

quicksort

em C utiliza uma tcnica bastante sosticada, inventada por Hoare, em

que o vector ordenado directamente, sem recorrer a outras estruturas de dados. Em resultado disso, o algoritmo executado muito rapidamente e exigindo muito pouca memria para alm da necessria para conter o vector. A implementao em Haskell por outro lado aloca muito mais memria e de execuo muito mais lenta que o a execuo em C. A implementao em C troca a complexidade por tempos de execuo reduzidos. Tal leva a concluir que em aplicaes em que o desempenho que se baseie em tempos de execuo seja um factor critico, as linguagens como C sero sempre uma melhor escolha do que o Haskell, precisamente porque lidam mais como a forma como as computaes so efectuadas. A distancia do Haskell ao

hardware

maior do que a do C, por isso consegue exprimir os algoritmos a

um nvel mais elevado, mas com menor nvel de controlo sobre a mquina. Verica-se que so poucos os programas que exigem grande desempenho medidos somente tendo por mtrica o tempo de execuo. Os entusiastas do Haskell defendem que se abandonou a escrita de programas em Assembler, deixando-a apenas para casos extremos de desempenho. Argumentam que os benefcios de se ter um modelo de programao mais prximo da inteno do programador compensa os custos que tal implica. Uma viso mais ousada posiciona as linguagens funcionais relativamente s imperativas da mesma forma que estas se posicionam relativamente ao Assembler. Provavelmente trata-se de uma assuno megalmana mas em termos estritos verica-se que em ambos os casos, os programas tm maior poder expressivo e menor controlo directos sobre a mquina. Da mesma forma verica-se que para a maioria dos programas, este compromisso aceitvel.

12

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 3

Aplicao de simplicao e derivao de expresses matemticas


3.1 Objectivo
O objectivo da aplicao solicitar uma expresso ao utilizador e calcular a expresso simplicada e a sua derivada. A aplicao foi desenvolvida em Haskell como caso de estudo de linguagens funcionais. A sintaxe das expresses matemticas prxima da notao algbrica tendo como principais caractersticas possibilidade de omisso de operadores implcitos, indicao de precedncias de operadores, notao inxa de operadores e incluso de algumas funes conhecidas. Os operadores suportados so os da adio, subtraco, multiplicao, diviso, potenciao e radiciao. A aplicao suporta algumas funes trigonomtricas, a funo logartmica e a funo exponencial. Os valores numricos das expresses podem ser quaisquer nmeros reais, sendo reconhecida apenas uma varivel. Para garantir a robustez do sistema, a aplicao inclui mecanismos de validao que testam a expresso introduzida do ponto de vista sintctico e semntico. A validao sintctica permite detectar situaes de erros de sintaxe como a existncia de smbolos no permitidos, sequncias de operadores no permitidas, funes no suportadas, balanceamento de parntesis, etc. Se um expresso estiver correcta do ponto de vista sintctico, efectuada de seguida uma validao semntica para detectar situaes de violaes de domnio das funes, divises por zero ou radicandos invlidos. S so efectuadas

simplicaes e derivaes de expresses que tenham sido examinadas e aprovadas pelo validador tanto do ponto vista sintctico como semntico. As seces seguintes apresentam a gramtica das expresses, a arquitectura da aplicao e os vericaes efectuadas nas validaes.

3.2 Gramtica das expresses


A aplicao efectua clculos com nmeros reais, exprimindo o resultado aproximado com nmeros racionais sob a forma decimal. A notao de varivel explicitada por um

x.

De forma a tornar

mais rpida e eciente a introduo de expresses, os operadores matemticos so representados por caracteres especcos. Por exemplo, a multiplicao, identicada na notao matemtica pelo smbolo

13

Testes de Programas em Haskell

Teste e Qualidade de Software

deve ser indicada pelo caracter

A prioridade dos operadores tambm a existente na notao

matemtica normal. A aplicao suporta as seguintes funes reais de varivel real: polinmios, funes trigonomtricas e trigonomtricas inversas, logartmica e exponencial. O formato com que o utilizador introduz uma expresso designado por

formato externo.

Embora

na validao e processamento, ocorram transformaes da expresso em outros formatos, o resultado das expresses produzidas obedece tambm a este formato. Uma denio formal desse formato obtida atravs de uma gramtica que explicita os operadores e funes admissveis, bem como as sequncias permitidas entre eles. A gura 3.1 apresenta a gramtica da aplicao atravs da sua escrita em EBNF (

Extended Backus-Naur Form ):

expressao ::= ( { expressao operador expressao | f uncao ( expressao )| inteiro | real |x} ) f uncao ::= sen|cos|tg |arcsen|arccos|arctg |log |exp operador ::= +| | |/| | digito ::= 0|1|2|3|4|5|6|7|8|9 inteiro ::= digito | inteiro digito real ::= inteiro . f raccao f raccao ::= digito | digito f raccao

Figura 3.1

Gramtica da aplicao representada em EBNF

As expresses podem ser constitudas por nmeros (inteiros ou racionais), variveis, operadores, funes e outras sub-expresses. A tabela 3.1 apresenta alguns exemplos de escrita de expresses matemticas em notao algbrica e na notao da gramtica da aplicao:

Notao algbrica
4x2 + 2x 3.05 x(x + 2)(x + 3)
x+1 x2 +25x
3

Notao da aplicao
4x2+2x3.05 x(x+2)(x+3) (x+1)/(x2+25x) 3|(2x+1)2 sen(x)2+cos(x)2 3sen(3x+4)cos(4-2x) (x2+3)(sen(3x)4) exp(x) (log(x)/x)2

(2x + 1)2

sen2 (x) + cos2 (x) 3sen(3x + 4) cos(4 2x) (x2 + 3)sen ex


(x) 2 ( logx )
4

(3x)

Tabela 3.1

Exemplos de expresses matemticas

14

Testes de Programas em Haskell

Teste e Qualidade de Software

3.3 Arquitectura da aplicao


O utilizador introduz a expresso no formato externo, que um formato simples e amigvel. No entanto, este formato no o mais conveniente para os processamentos que a aplicao efectua na simplicao e na derivao da expresso introduzida. Para realizar os clculos necessrios, a aplicao efectua sucessivas transformaes da expresso inicial, alterando-lhe o formato, convertendo-a para um formato interno e obtendo os seus elementos simples, formando uma estrutura lgica designada por

representao da expresso em rvore.

Esta

representao corresponde decomposio sintctica da expresso e a mais conveniente para efectuar processamentos seguintes. A estratgia de soluo implicou que tenham sido criados blocos funcionais para a execuo de tarefas especcas de cada transformao. A execuo desses blocos segue uma sequncia denida, numa lgica semelhante a uma linha de montagem, que pode ser organizada em trs grupos: preparao da expresso, transformao da expresso e apresentao da expresso transformada. A arquitectura segue um padro tpico em linguagens funcionais, ou seja, a de

pipes and lters.

gura 3.2 apresenta o diagrama da arquitectura da aplicao com os blocos constituintes de cada grupo.

Figura 3.2

Arquitectura da aplicao

Cada bloco funcional da arquitectura corresponde a uma funo especca, actuando o bloco como um ltro. Os blocos efectuam processamento e sempre que necessrio alteram o formato da entrada em outro que constitui a entrada para o bloco seguinte.

15

Testes de Programas em Haskell

Teste e Qualidade de Software

3.4 Blocos funcionais da aplicao


1.

Conversor para o formato interno


O formato externo permite que a introduo de expresses seja simples e amigvel para o utilizador, possibilitando variantes sintcticas que facilitam essa tarefa (

syntatic sugar ).

Por serem

permitidas omisses de operaes, este formato no se torna conveniente para a anlise e decomposio da expresso em elementos. O formato interno aquele em que todas as variantes sintcticas so substitudas pelas suas representaes completas, ocorrendo algumas transformaes expresso. O formato em que a expresso ca aps essas transformaes designa-se por

formato

interno.
2.

Validador sintctico
Aps ser convertida para o formato interno, a expresso pode ser submetida a testes de validao do ponto de vista sintctico. O objectivo detectar se a expresso obedece gramtica denida para a aplicao. Se houver alguma violao dessa gramtica, a expresso recusada, no sendo sujeita a mais processamento sendo o utilizador informado do erro ocorrido. A validao

efectuada atravs da vericao da ocorrncia de determinadas situaes. A tabela 6.2 indica as vericaes efectuadas e exemplos de situaes de ocorrncia de erro: 3.

Construtor de rvore (parser )


Se a expresso, no formato interno, for vlida, est em condies de ser substituda pela sua representao em rvore. A rvore (

parse-tree )

construda atravs da anlise lexical de cada

caracter da expresso, sendo o resultado nal um conjunto de elementos com uma organizao hierrquica. Cada elemento pode ser um nmero, uma varivel, uma operao ou uma funo

e possui uma estrutura prpria. A anlise do processo de construo da parse-tree est fora do mbito deste trabalho, bastando apenas a percepo que a rvore uma estrutura recursiva do seguintes tipo:

Elemento (Tipo, Coeficiente, Expoente, [Elemento])


Os tipos podem ser constantes, variveis, operaes (adio, multiplicao e potenciao) e funes (seno, co-seno, tangente, co-tangente, logartmo e exponencial). Note-se que no so decompostas operaes de diviso e radiciao. Esta omisso deve-se ao facto da aplicao, em vez de ser

forada a tratar mais dois casos, identicar uma diviso como uma multiplicao pelo inverso de um nmero e uma radiciao como uma potncia de expoente fraccionrio.

4.

Simplicador e validador semntico


O simplicador analisa a representao em rvore da expresso e procura reduzir essa rvore, atravs de um conjunto de operaes, simplicando somas, produtos, potncias, aplicao de funes entre outras. Paralelamente tarefa de simplicao, este bloco tambm responsvel por efectuar a validao semntica, ou seja, vericar se as sub-expresses, aps tentativa de simplicao tm signicado sob ponto de vista matemtico. A tabela

??

indica as vericaes

efectuadas e exemplos de situaes de erros: A partir da representao inicial da rvore da expresso no possvel determinar se existem violaes de domnio, uma vez que s durante a

16

Testes de Programas em Haskell

Teste e Qualidade de Software

simplicao que so efectuadas as operaes algbricas. Antes de efectuar qualquer operao que possa levar a violao de domnio, os operandos so testados. Se for detectada uma das trs situaes anteriores, a operao no efectuada e o erro colocado na prpria rvore da expresso.

5.

Derivador
O derivador analisa a representao em rvore da expresso e cria novos elementos para cada elemento analisado. O conjunto dos novos elementos criados constitui a representao em rvore da derivada. A regra de derivao fornece indicaes de como construir o elemento da derivada correspondente a uma expresso. So indicadas operaes e o papel dos sub-elementos como operandos. frequente tambm a necessidade de derivar os sub-elementos e incluir a sua derivada na rvore. Cada elemento da rvore da expresso substitudo por um outro que corresponde regra de derivao a aplicar a esse tipo. A primeira regra de derivao a aplicar obtida a partir do

primeiro elemento da rvore, que corresponde operao de menor prioridade da expresso. O processo de derivao, tal como o de simplicao, recursivo. Uma vez obtida toda a rvore

resultante de uma derivao, essa rvore simplicada pelo mesmo bloco que simplicou inicialmente a expresso.

6.

Construtor de expresso
Para ser possvel apresentar o resultado nal do processamento da representao em rvore de uma expresso, necessrio convert-la novamente para uma expresso no formato interno (com notao inxa).

7.

Conversor para o formato externo


Para se terminar a fase de apresentao do resultado, apenas necessrio omitir o operador de adio nas parcelas de valor negativo. Aps esta converso, a expresso est no formato externo (em linguagem algbrica de fcil compreenso pelo utilizador) e pode ser apresentada.

17

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 4

Framework de testes HUnit 1.0


A HUnit uma

framework

de testes unitrios para a linguagem Haskell, inspirada na ferramenta JUnit

de igual propsito para Java. Foi desenvolvida em 2002 por Dean Herington encontrando-se ainda na sua verso 1.0. Utilizando a HUnit, tal como a JUnit, simples criar testes, atribuir-lhes nomes, agrup-los em suites e execut-los, deixando a vericao dos resultados ao cargo da

framework.

A especicao de

testes em HUnit ainda mais exvel do que em JUnit, devido natureza da linguagem Haskell. De momento, a HUnit s inclui um controlador baseado em texto, no entanto, a

framework

est desenhada

de forma a ser facilmente extendida e acomodar outros tipos de controladores. As seces seguintes exploram a

framework

com exemplos da utilizao na Aplicao de simplicao

e derivao de expresses matemticas apresentada previamente.

4.1 Asseres
Uma

assero

o bloco mais bsico para a construo de um teste e dene-se como sendo a armao

de que uma proposio verdadeira. No contexto de uma linguagem de programao, essa proposio pode assumir a forma de uma condio passvel de ser avaliada como verdadeira ou falsa. A assero sobre essa condio equivale a armar que ela verdadeira. As asseres so combinadas de forma a serem includas em casos de teste e de igual forma, vrios casos de teste formam uma suite de testes. No contexto da linguagem Haskell, a

framework

HUnit dene um tipo de dados especco para

representar asseres, ou seja, como uma computao IO:

type Assertion = IO ()
O tipo

IO

indica uma computao da mesma forma com que o tipo

Integer

indica inteiro e

Bool

indica um valor lgico. Numa abordagem simples, pode pensar-se em computaes como funes que aceitam um estado do sistema como argumento e retornam um par constitudo pelo estado do sistema actualizado e um resultado. Dentro dessa funo ocorre uma sequncia de computaes de tipo

IO

que

podem alterar o estado do sistema. Exemplos disso sero a entrada e sada de caracteres ou a leitura e escrita de cheiros.

18

Testes de Programas em Haskell

Teste e Qualidade de Software

Num programa em Haskell, as expresses do tipo presses. Na realidade, o tipo

IO

comportam-se como quaisquer outras ex-

IO

insere-se numa classe especial de construes da linguagem Haskell

denominadas Monads, que um dos seus tpicos mais complexos. A discusso de Monads est fora do mbito desta anlise e no crtica para os seus objectivos. suciente encarar o tipo tipo que retorna informao para o exterior. As asseres so assim computaes

IO

como um

IO que embora possam alterar o estado do sistema ao produzirem IO


para permitir que programas com efeitos

resultados para o exterior, no retornam resultados como as funes tipicamente fazem. A motivao das asseres serem representadas como computaes

laterais possam ser testados. A utilidade de uma assero a sinalizao de um sinal de erro, invocando a funo

assertFailure,

que lana uma excepo assinalada por uma mensagem:

assertFailure :: String -> Assertion assertFailure msg = ioError(userError ("HUnit:" ++ msg))


Na realidade, a funo valor retornado de tipo A

assertFailure ela prpria Assertion, logo de tipo IO.

uma computao j que na sua assinatura, o

framework

dene trs tipos de asseres.

Para cada tipo, a funo de construo da assero

diferente, no entanto, o resultado sempre de tipo

Assertion.

Todas utilizam a computao

assertFailure

quando pretendem sinalizar que a assero falsa.

Utilizando o mecanismo de

binding

(que no uma atribuio, j que tal construo no existe em

linguagens funcionais), possvel associar um identicador a uma assero. Os tipos de asseres so os seguintes:

Booleana
Arma que uma expresso booleana verdadeira. Pode ser indicada uma mensagem de erro para o caso em que a assero seja avaliada como falsa quando executada num caso de teste.

assertBool :: String -> Bool -> Assertion assertBool msg b = unless b (assertFailure msg)
A aplicao de simplicao e derivao de expresses matemticas inclui uma funo que verica se uma

isNumber

string

pode ser tratada como um nmero, ou seja, se no contem caracteres

no numricos. A funo retorna um valor booleano, pelo adequada para ser testada por este tipo de assero. Com esta funo possvel denir duas asseres booleanas:

assercao1 = assertBool "isNumber 2.5" (isNumber "2.5") assercao2 = assertBool "isNumber 2a5" (isNumber "2a5")
Quando forem includas num caso de teste, a primeira assero seria avaliada como verdadeira e a segunda como falsa pois inclui o caracter

que no numrico.

String
Arma que uma

string

nula. A mensagem de erro a prpria

string, caso a assero seja avaliada

como falsa quando executada num caso de teste.

19

Testes de Programas em Haskell

Teste e Qualidade de Software

assertString :: String -> Assertion assertString str = unless (null str) (assertFailure str)
A aplicao de simplicao e derivao de expresses matemticas inclui uma funo que extrai uma

substr

substring de outra mediante a indicao de posies de inicio e m. A funo retorna uma string resultante da extraco, pelo que adequada pode ser testada por este tipo de assero. Com esta funo possvel denir duas asseres de string :
assercao1 = assertString (substr "2x+3" 0 0) assercao2 = assertString (substr "2x+3" 1 3)

Quando forem includas num caso de teste, a primeira assero seria avaliada como verdadeira, retorna uma

string

nula, e a segunda como falsa pois retorna uma

string

no nula.

Igualdade
Arma que duas expresses so iguais. As expresses podem ser de qualquer tipo, no entanto, tm que entre elas ser do mesmo tipo. Pode ser indicada uma mensagem de erro para o caso em que a assero seja avaliada como falsa quando executada num caso de teste.

assertEqual :: (Eq a, Show a) => String -> a -> a -> Assertion assertEqual mensagem esperado avaliado = unless (avaliado == esperado) (assertFailure mensagem) where msg = (if null mensagem then "" else mensagem ++ "\n") ++ "expected: " ++ show esperado ++ "\n but got: " ++ show avaliado
A aplicao de simplicao e derivao de expresses matemticas inclui uma funo que simplica uma expresso matemtica indicada numa string.

simplif

A funo retorna uma

string

resultante da simplicao, pelo que adequada pode ser testada por este tipo de assero. Com esta funo possvel denir duas asseres de igualdade. Alm da mensagem de erro, indica-se a expresso esperada e de seguida a expresso que deve ser avaliada para ser comparada com a esperada:

assercao1 = assertEqual "Simplificao: 2x+1+3x+4" "5x+5" (simplif "2x+1+3x+4") assercao2 = assertEqual "Simplificao: 2x+1+3x+4" "8x-2" (simplif "2x+1+3x+4")
Quando forem includas num caso de teste, a primeira assero seria avaliada como verdadeira, a expresso esperada igual avaliada, e a segunda como falsa, onde tal no acontece.

A denio de asseres por si s no tem aplicao prtica, necessrio inclu-las em casos de teste. durante a execuo de casos de teste que se avaliam as asseres de qualquer um dos trs tipos.

20

Testes de Programas em Haskell

Teste e Qualidade de Software

4.2 Casos de teste


Um

caso de teste consiste num conjunto de uma ou vrias asseres.

Os casos de teste so independentes

entre si, ou seja, a execuo de uns no est dependente da execuo de outros. Por outro lado, se um caso de teste incluir vrias asseres, a sua execuo no independente. Se uma assero no conjunto for avaliada como falsa, as seguintes j no sero avaliadas. Este raciocnio til para denir uma

lgica de testes incrementais em que existem funcionalidades que dependem umas das outras. Se uma funcionalidade falhar numa assero, no far sentido testar outra que depende do resultado errada da primeira. Independentemente do nmero de asseres que possa incluir, a criao de um caso de teste efectuada com o construtor

TestCase.

O caso de teste pode indicar directamente uma assero ou

referenciar um identicador de uma (ou vrias) j criadas. A cada caso de teste pode ser associado um identicador com o mecanismo de binding (como acontece com as asseres).

TestCase :: Assertion -> Test cteste1 = TestCase assercao1 cteste2 = TestCase (assertString (substr "2x+3" 1 3))
No primeiro exemplo criado um caso de teste a partir do identicador identicador

assercao1

e associa-o ao

teste1.

No segundo exemplo criado um caso de teste a partir de uma assero de

string

e associa-o ao identicador

teste2.

No exemplo seguinte, o caso de teste composto por duas asseres com ordem de precedncia:

cteste = TestCase (do assertEqual ("fmt_int: "++expressao) esperado fmt_int assertEqual ("fmt_ext: "++expressao) expressao fmt_ext) where expressao = "3x^2-3x+4" esperado = "3*x^2+-3*x+4" fmt_int = ext2int expressao fmt_ext = int2ext fmt_int
A construo com A construo

do

necessria para conseguir colocar duas ou mais asseres num caso de teste.

where

dene

bindings

a serem utilizados nas asseres.

O objectivo deste caso de teste vericar se na aplicao de simplicao e derivao de expresses matemticas uma expresso correctamente convertida do formato externo para o interno e vice-versa. Sendo funes simtricas, podem ser incorporadas no mesmo caso de teste, mas s faz sentido avaliar a segunda se a primeira produzir resultados satisfatrios. A expresso associada ao identicador externo. A expresso associada ao no formato interno.

expressao o identicador esperada

objecto do teste e encontra-se no formato corresponde transformao da expresso

avaliado o formato interno com a funo ext2int e associado ao identicador

fmt_int.

A primeira assero utiliza construda com base nestes identicadores.

avaliado o formato externo com a funo

int2ext

e associado ao identicador

fmt_ext.

expresso esperada na segunda assero a que inicialmente convertida para o formato interno, ou seja, associada ao identicador

expressao.

Garante-se que na execuo deste caso de teste, a segunda assero s ser avaliada se a primeira for verdadeira.

21

Testes de Programas em Haskell

Teste e Qualidade de Software

4.3 Agrupamento de testes


Dene-se um

teste

como um conjunto de casos de teste.

A distino entre teste e caso de teste no

existe em HUnit. A funo

TestCase

retorna sempre um valor de tipo

Test.

este facto que permite

que um teste possa ser um conjunto de casos de teste ou um conjunto de testes. Num ambiente de testes, assim que o nmero de testes comea a aumentar recomendvel formar grupos de testes para os processar mais facilmente. Os identicadores por

binding

facilitam apenas a

tarefa do programador de testes. A capacidade de poder atribuir nomes a testes sob a forma de labels (

strings ) facilita a sua identicao em tempo de execuo.

O agrupamento de testes e a atribuio de

nomes a testes (ou grupos de testes) so as duas formas que o HUnit disponibiliza para gerir grandes coleces de testes. O tipo de dados possvel:

Test

denido de forma a poder construir testes com a mxima exibilidade

data Test = TestCase Assertion | TestList [Test] | TestLabel String Test


Desta denio salientam-se os seguintes aspectos:

Uma

TestList

uma lista de testes em vez de uma lista de casos de teste. Tal implica que a Desta forma, os testes podem ser organizados da mesma

estrutura de um teste uma rvore.

forma que cheiros so organizados num sistema operativo.

O nome,

TestLabel,

uma

string

associada a um teste em vez de a um caso de teste.

Tal

implica que a todos os ns da rvore pode ser associado um nome. Esta caracterstica facilita a organizao dos testes.

Uma

TestLabel

um conceito separado de um caso de teste ou uma lista de testes. Tal implica

que opcional associar um nome a um teste. benco que assim seja, pois em certas situaes pode ser desnecessrio e inconveniente ter se associar sempre um nome a cada n de uma grande rvore de testes. Um exemplo na aplicao de simplicao e derivao de expresses matemticas a seguinte suite de testes:

tSNumeros = TestCase (assertEqual "Simplificacao:" "9" (simplif "2+7")) tSMonomios = TestCase (assertEqual "Simplificacao:" "9x" (simplif "2x+7x")) tSPolinomio = TestCase (assertEqual "Simplificacao:" "12x^2+4x+5" (simplif "3x^2+9x^2+3x+5+x")) tSomas = TestLabel "Somas" (TestList [TestLabel "Numeros" tSNumeros, TestLabel "Monomios" tSMonomios, TestLabel "Polinomio" tSPolinomio]) tPNumeros = TestCase (assertEqual "Simplificacao:" "14" (simplif "2*7")) tPMonomios = TestCase (assertEqual "Simplificacao:" "14x^2" (simplif "2x*7x"))
22

Testes de Programas em Haskell

Teste e Qualidade de Software

tPPolinomio

= TestCase (assertEqual "Simplificacao:" "405x^6" (simplif "3x^2*9x^2*3x*5*x"))

tProd

= TestLabel "Produtos" (TestList [TestLabel "Numeros" tPNumeros, TestLabel "Monomios" tPMonomios, TestLabel "Polinomio" tPPolinomio])

suiteTP = TestLabel "Polinmios" (TestList [tSomas, tProd])


Esta suite de testes agrega testes de simplicao de produtos e somas. A simplicao de somas agrega por sua vez trs testes, um com nmeros, outro com monmios e outro com um polinmio. A simplicao de produtos agrega testes idnticos para produtos. Todos os testes tm um nome associado. O teste que dene a suite de testes foi nomeado de Polinomios. Os dois testes agrupadores tm o nome de Somas e Produtos. Os nomes dos testes que agregam outros testes servem para contextualizar os testes elementares. H um par de testes o nome Numeros, Monomios e Polinomio respectivamente. Durante a execuo dos testes, como so includos os nomes dos testes agrupadores nunca ocorre perda de contexto. Os nomes associados assero referem-se funcionalidade que est a ser testada, que sempre a simplicao de expresses matemticas. A suite de testes pode ser representada por uma rvore de testes, como a da gura 4.1:

Figura 4.1

Suite de testes de simplicao

4.4 Contagem de casos de teste


possvel contar o nmero de casos de teste que esto includos num n da rvore, utilizando a funo

testCaseCount. testCaseCount :: Test -> Int


A funo tem como argumento um teste e retorna um nmero inteiro que indica quantos testes esto includos. O teste indicado como argumento normalmente ser um teste agregador j que a contagem

23

Testes de Programas em Haskell

Teste e Qualidade de Software

para testes com asseres ser sempre de 1 (no incluem outros testes). O resultado da contagem, no entanto, s inclui os testes com asseres, no entrando para a contagem todos os testes que sirvam para agregar outros. A tabela 4.1 inclui os trs casos relevantes de contagem para a suite de testes da gura 4.1:

Comando
testCaseCount tSNumeros testCaseCount tSomas testCaseCount suiteTP

Contagem
1 3 6

Tabela 4.1

Contagem de casos de teste da suite de testes

Criando um novo teste na rvore no mesmo nvel dos testes agregadores Soma e Produto para o tratamento de simplicao de potncias:

tPoten = TestCase (assertEqual "Simplificacao:" "8" (simplif "2^3"))


A suite de testes tm que ser alterada de forma a incluir este teste:

suiteTP = TestLabel "Polinmios" (TestList [tSomas, tProd, tPoten])


Passando a ser representada pela rvore de testes da gura 4.2:

Figura 4.2

Variante suite de testes de simplicao

A tabela 4.2 inclui os trs casos relevantes de contagem para a suite de testes da gura 4.2:

Comando
testCaseCount tSNumeros testCaseCount tSomas testCaseCount suiteTP

Contagem
1 3 7

Tabela 4.2

Contagem de casos de teste da variante da suite de testes

O nmero de casos de teste contado a partir da raiz da arvore aumenta para 7, porque o teste um teste com uma assero.

tPoten

24

Testes de Programas em Haskell

Teste e Qualidade de Software

4.5 Caminhos na hierarquia de testes


A forma de identicar univocamente um teste na rvore de testes indicando o seu caminho desde a raiz. O caminho denido como a sequncia de ns entre a raiz e o teste em causa. Para o efeito, o HUnit dene o tipo de dados tipo de dados

Node

que pode ser um

ListItem

ou uma

Label

e o

Path

que uma lista de ns:

data Node = ListItem Int | Label String deriving (Eq, Show, Read) type Path = [Node]
O tipo tipo:

Node

est associado ao tipo

Test,

que dene a forma de agrupar testes. Revisitando este

data Test = TestCase Assertion | TestList [Test] | TestLabel String Test


verica-se que cada sub-lista de testes (TestList) includa no caminho como uma cada denio de nome (TestLabel) includa no caminho como uma

ListItem

Label.

A unicidade de um teste garantida somente pelo inteiro em ListItem, no entanto, se existir um nome para o teste, este includo pela seguindo-se o um, dois, etc. A ordem dos ns no caminho de baixo para cima, ou seja, do teste para o n de raiz que agrega todos os testes. Desta forma mais simples de comparar caminhos j que os que prexos comuns podem ser partilhados. Para apresentao dos caminhos que um teste comporta, utiliza-se a funo caminhos so listados na mesma ordem com que os testes sero executados.

Label.

A numerao dos testes inicia-se com o nmero zero,

testCasePaths.

Os

testCasePaths :: Test -> [Path]


A funo recebe um teste, ou seja, qualquer n da rvore, e apresenta uma lista com todos os caminhos dos testes que esse n inclui. Alguns exemplos dos resultados da funo aplicados rvore da gura 4.2: 1. Caminhos a partir de um teste com uma assero

testCasePaths tSNumeros [[]]


O resultado uma lista vazia, j que testes com asseres no podem incluir outros testes. 2. Caminhos a partir de um teste agregador de testes com asseres:

testCasePaths tSomas [[Label "Nmeros", ListItem 0, Label "Somas"], [Label "Monomios", ListItem 1, Label "Somas"], [Label "Polinomio", ListItem 2, Label "Somas"]]
O resultado uma lista com os trs testes com asseres com indicao do seu nome (Label) e

25

Testes de Programas em Haskell

Teste e Qualidade de Software

nmero (ListItem). No m de cada caminho tambm includo o nome do teste agregador, neste caso

Somas.

3. Caminhos a partir da raiz da rvore de testes:

testCasePaths suiteTP [[Label "Nmeros", ListItem 0, Label [Label "Monomios", ListItem 1, Label [Label "Polinomio", ListItem 2, Label [Label "Nmeros", ListItem 0, Label [Label "Monomios", ListItem 1, Label [Label "Polinomio", ListItem 2, Label [ListItem 2, Label "Polinmios"]]

"Somas", "Somas", "Somas", "Produtos", "Produtos", "Produtos",

ListItem ListItem ListItem ListItem ListItem ListItem

0, 0, 0, 1, 1, 1,

Label Label Label Label Label Label

"Polinmios"], "Polinmios"], "Polinmios"], "Polinmios"], "Polinmios"], "Polinmios"],

O resultado uma lista com os todos os caminhos para os casos de teste com asseres, que como se vericou na tabela 4.2, so sete. Note-se que o ltimo caso no tem

Label, tendo s ListItem.

Tal deve-se ao facto de no ter sido denida qualquer nome para este teste. A nica forma do caminho se referir a ele indicando que o teste n

o 2 na sequncia da rvore.

O resultado dos caminhos da raiz da rvore identica a framework atribu automaticamente um nmero aos testes, como se pode vericar na gura 4.3:

Figura 4.3

Suite de testes de simplicao com numerao

Partindo do teste em direco raiz da rvore, a funo identicou os caminhos de teste indicados na tabela 4.3, atravs de nmeros e atravs de nomes:

Nmeros
0 0 0 1 1 1 2 0 1 2 0 1 2

Nomes
Nmeros Somas Polinmios Monmios Somas Polinmios Polinmio Somas Polinmios Nmeros Produtos Polinmios Monmios Produtos Polinmios Polinmio Produtos Polinmios Polinmios
Caminhos na hierarquia de testes

Tabela 4.3

26

Testes de Programas em Haskell

Teste e Qualidade de Software

4.6 Execuo de testes


Contadores de testes
A execuo de um teste envolve um execuo srie (atravs do Monad IO) dos seus casos de teste constituintes. Os casos de testes so executados por ordem decrescente de profundidade, ou seja, so executados os mais profundos primeiro e da esquerda para a direita na mesma profundidade. Durante a execuo, so mantidos quatro contadores, numa estrutura de dados de tipo

Count:

data Counts = Counts {cases, tried, errors, failures :: Int} deriving (Eq, Show, Read)
Os quatro elementos da estrutura so valores inteiros cujo valor vai sendo alterado durante a execuo de um teste:

cases

 Nmero de testes includos no teste, s sendo superior a um para o caso dos testes

agregadores. Este valor uma propriedade esttica de um teste e permanece inalterado durante a execuo.

tried

 Nmero de testes tentados, ou seja, executados at ao momento (durante uma execuo

de testes).

errors

 Nmero de testes cuja execuo abortou devido ocorrncia de uma excepo inesper-

ada. Estes erros acusam problemas com o teste e no com o cdigo a ser testado.

failures

 Nmero de testes em que pelo menos uma assero foi avaliada como falsa.

Estes

erros acusam problemas com o cdigo a ser testado. No existe nenhum contador para os casos de teste bem sucedidos. H dois motivos para que assim seja. Por um lado esse valor facilmente calculvel atravs de:

tried - (errors + failures))


O outro motivo de ordem psicolgica. Espera-se sempre que o foco da ateno do testador seja para os casos que falham. Os casos que passam no teste sero tipicamente a maioria. para a minoria dos casos que falham nos testes que toda ateno deve ser canalizada, da que o destaque nos prprios contadores seja para essas situaes.

Controladores de testes
Os testes em HUnit so executados por um processo denominado Controlador de teste. Este processo tem sempre o mesmo modelo de execuo, no entanto, pode apresentar os resultados de forma distinta. medida que a execuo do teste progride, so lanados trs tipos de eventos para o controlador de teste. Cada controlador pode responder de forma distinta aos eventos, variando normalmente na forma como os apresenta:

Incio  antes da inicializao da execuo de teste reporta-se o seu caminho e estado;

27

Testes de Programas em Haskell

Teste e Qualidade de Software

Erro  sempre que um caso de teste termina devido deteco de um erro, reportada a mensagem de erro, o caminho e o estado actual do teste;

Falha  sempre que um caso de teste termina devido a uma falha, a mensagem de falha reportada, o caminho e o estado actual do teste.

Tipicamente, um controlador de teste apresenta os relatrios de erros e falha imediatamente mas utiliza o relatrio de inicio meramente para actualizar o progresso no estado de execuo. O Hunit inclui apenas um controlador de testes que baseado em texto, no entanto, o utilizador pode denir outros para obter variaes na apresentao dos testes. A funo que implementa o controlador de testes nativo da framework a

runTestText:

runTestText :: PutText st -> Test -> IO (Counts, st)


O controlador de testes pode ser um pouco adaptado atravs da indicao de um esquema de apresentao (

reporting scheme ), que corresponde ao primeiro argumento. string

O teste a executar indicado

no segundo argumento. Durante a execuo, o controlador cria uma acordo com o esquema de apresentao. para cada evento a reportar e processa-a de

Quando a execuo do teste est completa, o controlador

retorna os contadores e o estado nal para o esquema de reporte (de tipo par As

IO (Counts, st))

strings

para cada um dos eventos de reporte so as seguintes: o resultado da funo

Um

showCounts aplicado aos contadores imediatamente antes da inicializao do caso de teste a ser executado: A funo showCounts apresenta o conjunto de contadores da estrutura Counts como uma string : showCounts :: Counts -> String
O resultado tem o seguinte aspecto:

reporte de incio

onde

"Cases: num_cases Tried: num_tried Errors: errors Failures: failures" num_cases, num_tried, num_errors e num_failures so os valores contados durante
apresentado como:

execuo.

Um

reporte de erro

onde

"### Error in: message" path o caminho "### Error: message"

path
do caso de teste em que ocorreu o erro e

message

a mensagem que

descreve o erro. Se o caminho for vazio, o reporte apresentado da forma:

A funo

showPath

a responsvel por apresentar o caminho de um teste num

string,

aceitando

um caminho como argumento:

showPath :: Path -> String


Recorde-se que funo que obtm o caminho de um teste (testCasePaths) faculta-o com os ns desde o teste at raiz da rvore. A funo

showPath

pelo contrrio apresenta o caminho com

os ns desde a raiz at ao teste (efectua uma inverso da lista de ns que recebe). Os ns so apresentados separados pelo delimitador

":".

A representao de

(ListItem n) com (show n).

28

Testes de Programas em Haskell

Teste e Qualidade de Software

Um

reporte de falha

apresentado como:

onde

"### Failure in: path message" path o caminho do caso "### Failure: message"

de teste em que ocorreu o erro e

message

a mensagem que

descreve o erro. Se o caminho for vazio, o reporte apresentado da forma:

Esquemas de apresentao
O HUnit inclui dois esquemas de apresentao para controladores baseados em texto. entanto, ser denidos outros conforme for a convenincia do programador. numa funo especca: 1. A funo um Podem, no Cada esquema baseia-se

putTextToHandle escreve reportes de erro, reportes de falha e o de contagem de nal para


indicado. O

handle

handle

pode ser um cheiro, um terminal ou qualquer outro dispositivo

de sada.

putTextToHandle :: Handle -> Bool -> PutText Int


Cada um destes reportes terminado por um carcter de indicada for por uma

newline.

Para alm disso, se a ag

True,

tambm includa a escrita do reporte de inicio, no sendo este terminado

newline.

Antes do reporte seguinte ser escrito, o reporte de inicio apagado com uma

sequncia apropriada de

carriage return

e caracteres de espao, para produzir os efeitos desejados

em terminais. No conveniente que assim seja em cheiros pois produz linhas em branco no necessrias. 2. A funo

putTextToShowS

ignora reportes de incio e simplesmente acumula reportes e erro e

falhas, terminando com

newlines.

putTextToShowS :: PutText ShowS


Os reportes de acumulao so retornados (sendo o segundo elemento do par retornado por

runTestText)

como uma funo

ShowS

(ou seja, uma com a assinatura

String -> String)

cujo

primeiro argumento uma O HUnit fornece a funo

string

a ser concatenada s linhas de reporte j acumuladas. que serve de atalho para a utilizao mais comum de um

runTestTT

controlador baseado em texto.

A funo

runTestTT

invoca a funo

runTestText,

especicando

putTextToHandle stderr True

para o esquema de apresentao (com

handle

para o terminal) e re-

torna a contagem nal da execuo do teste. A implementao a seguinte:

runTestTT :: Test -> IO Counts runTestTT t = do (counts, 0) <- runTestText (putTextToHandle stderr True) t return counts

29

Testes de Programas em Haskell

Teste e Qualidade de Software

Exemplos de execuo de testes


Exemplos de utilizao da funo

runTestTT

para execuo de testes na rvore da gura 4.2:

Execuo de um caso de teste isolado


Recorde-se a construo do caso de teste de somas num polinmio (corresponde a um dos ns mais profundos da rvore):

tSPolinomio = TestCase (assertEqual "Simplificacao:" "12x^2+4x+5" (simplif "3x^2+9x^2+3x+5+x"))


A assero avaliada como verdadeira logo a execuo no reporta erros, sendo apenas apresentados os reportes de incio e de m:

runTestTT tSPolinomio Cases: 1 Tried: 0 Errors: 0 Failures: 0 Cases: 1 Tried: 1 Errors: 0 Failures: 0

reporte de incio ) (reporte de m )


(

Alterando o teste de modo que a assero seja avaliada como falsa, por alterao do polinmio esperado:

tSPolinomio = TestCase (assertEqual "Simplificacao:" "10x^2+8x+3" (simplif "3x^2+9x^2+3x+5+x"))


A execuo acusa a presena da falha e contabiliza-a no reporte de m:

runTestTT tSPolinomio Cases: 1 Tried: 0 Errors: 0 Failures: 0 ### Failure: Simplificacao: expected: "10x^2+8x+3" but got: "12x^2+4x+5" Cases: 1 Tried: 1 Errors: 0 Failures: 1

( (

reporte de incio ) reporte de falha )

reporte de m )

Execuo de um teste agregador


Retirando a falha no caso de teste anterior referente a somas num polinmio, executa-se o teste agregador com o nome

Somas :
0 1 2 3 Errors: Errors: Errors: Errors: 0 0 0 0 Failures: Failures: Failures: Failures: 0 0 0 0

runTestTT Cases: 3 Cases: 3 Cases: 3 Cases: 3

tSomas Tried: Tried: Tried: Tried:

reporte (reporte (reporte (reporte


(

de de de de

incio ) m do teste 1 ) m do teste 2 ) m do teste 3 )

Voltando a injectar a mesma falha na soma de polinmios, a execuo acusa o erro no caso de teste respectivo na sequncia dos outros casos de teste:

runTestTT tSomas Cases: 3 Tried: 0

Errors: 0 Failures: 0
30

reporte de incio )

Testes de Programas em Haskell

Teste e Qualidade de Software

Cases: 3 Tried: 1 Errors: 0 Failures: 0 Cases: 3 Tried: 2 Errors: 0 Failures: 0 ### Failure: Somas:2:Polinomio Simplificacao: expected: "10x^2+8x+3" but got: "12x^2+4x+5" Cases: 3 Tried: 3 Errors: 0 Failures: 0

reporte de m do teste 1 ) (reporte de m do teste 2 ) (reporte de falha do teste 3 )


(

reporte de m do teste 3 )

Execuo da suite de testes


Retirando novamente a falha no caso de teste referente a somas num polinmio, executa-se toda a suite de testes com o nome

Polinmios :
0 0 0 0 0 0 0 0 Failures: Failures: Failures: Failures: Failures: Failures: Failures: Failures: 0 0 0 0 0 0 0 0

runTestTT Cases: 3 Cases: 3 Cases: 3 Cases: 3 Cases: 3 Cases: 3 Cases: 3 Cases: 3

suiteTP Tried: 0 Tried: 1 Tried: 2 Tried: 3 Tried: 4 Tried: 5 Tried: 6 Tried: 7

Errors: Errors: Errors: Errors: Errors: Errors: Errors: Errors:

reporte (reporte (reporte (reporte (reporte (reporte (reporte (reporte


(

de de de de de de de de

incio ) m do teste m do teste m do teste m do teste m do teste m do teste m do teste

1) 2) 3) 4) 5) 6) 7)

Injectando a falha anterior e uma outra por alterao do caso de teste:

tPMonomios = TestCase (assertEqual "Simplificacao:" "15x^3" (simplif "2x*7x"))


A execuo reporta as duas falhas pela ordem em que os respectivos testes so executados na rvore (note-se a indicao dos caminhos dos casos de teste):

runTestTT suiteTP Cases: 7 Tried: 0 Errors: 0 Failures: 0 Cases: 7 Tried: 1 Errors: 0 Failures: 0 Cases: 7 Tried: 2 Errors: 0 Failures: 0 ### Failure in: Polinmios:0:Somas:2:Polinomio Simplificacao: expected: "10x^2+8x+3" but got: "12x^2+4x+5" Cases: 7 Tried: 3 Errors: 0 Failures: 1 Cases: 7 Tried: 4 Errors: 0 Failures: 1 ### Failure in: Polinmios:1:Produtos:1:Monomios Simplificacao: expected: "15x^3" but got: "14x^2" Cases: 7 Tried: 5 Errors: 0 Failures: 2 Cases: 7 Tried: 6 Errors: 0 Failures: 2 Cases: 7 Tried: 7 Errors: 0 Failures: 2
31

reporte reporte (reporte (reporte


( (

de de de de

incio ) m do teste 1 ) m do teste 2 ) falha do teste 3 )

reporte de m do teste 3 ) (reporte de m do teste 4 ) (reporte de falha do teste 5 )


(

reporte de m do teste 5 ) (reporte de m do teste 6 ) (reporte de m do teste 7 )


(

Testes de Programas em Haskell

Teste e Qualidade de Software

4.7 Funcionalidades avanadas


O HUnit inclui funcionalidades adicionais para especicar asseres e testes de forma ainda mais concisa e prtica. Para a sua implementao, a

framework

utiliza as classes de tipos do Haskell.

Operadores de construes de asseres


Podem ser utilizados os operadores seguintes para construir asseres:

Operador
pred @? msg expected @=? actual actual @?= expected

Assero criada
assertionPredicate pred >>= assertBool msg assertEqual "" expected actual assertEqual "" expected actual
Operadores de construo de asseres

Tabela 4.4
No operador na funo

@? indica-se uma condio booleana e uma mensagem de erro separadamente, tal como assertBool mas com diferente ordem. Os operadores @=? e @?= fornecem uma forma abreviada de criar asseres de igualdade com a funo assertEqual, quando no necessria mensagem de erro. Diferem apenas na ordem com que
os operandos so indicados (valor esperado e valor avaliado). No mbito da aplicao de derivao e simplicao de expresses matemticas, algumas asseres podem ser escritas mais facilmente:

Operao
(isNumber "2.5") @? "isNumber 2.5" "5x+5" @=? (simplif "2x+1+3x+4") (simplif "2x+1+3x+4") @?= "5x+5"

Assero criada
assertBool "isNumber 2.5" (isNumber "2.5") assertEqual "" "5x+5" (simplif "2x+1+3x+4") assertEqual "" "5x+5" (simplif "2x+1+3x+4")

Tabela 4.5

Exemplos de construes de asseres com operadores

Sobrecarga de funes de asseres


Outra forma de construir asseres utilizar a funo com sobrecarga

assert

da classe de tipo

Assertable: class Assertable t where assert :: t -> Assertion instance Assertable () where assert = return instance Assertable Bool where assert = assertBool ""

32

Testes de Programas em Haskell

Teste e Qualidade de Software

instance (ListAssertable t) => Assertable [t] where assert = listAssert instance (Assertable t) => Assertable (IO t) where assert = (>>= assert)
A classe

ListAssertable permite que a funo assert possa ser aplicada a uma lista de caracteres

[Char],

ou seja, uma

string :

class ListAssertable t where listAssert :: [t] -> Assertion instance ListAssertable Char where listAssert = assertString
Com as declaraes indicadas possvel denir asseres que nunca falham, tais como:

assert () assert True assert ""


Tambm possvel denir asseres que falham sempre, tais como:

assert False assert "some failure message"


possvel denir outras instncias para as classes de tipos

Assertable, ListAssertable

AssertionPredicable

que possam ser teis no contexto de uma aplicao em particular.

Operadores de construes de testes


Podem ser utilizados os operadores seguintes para construir testes:

Operador
pred ~? msg expected ~=? actual actual ~?= expected label ~: t

Teste criado
TestCase (pred @? msg) TestCase (expected @=? actual) TestCase (actual @?= expected) TestLabel label (test t)

Tabela 4.6
Os operadores

Operadores de construo de testes

~?, ~=?

~?=

construem uma assero e um caso de teste para essa assero. So

utilizados da mesma forma que os operadores O operador

@?, @=?

@?=

s que constroem imediatamente o teste.

~:

associa um nome (

label ) a um teste j existente.

33

Testes de Programas em Haskell

Teste e Qualidade de Software

No mbito da aplicao de derivao e simplicao de expresses matemticas, alguns testes podem ser escritos mais facilmente :

Operao
(isNumber "2.5") ~? "isNumber 2.5" "5x+5" ~=? (simplif "2x+1+3x+4") (simplif "2x+1+3x+4") ~?= "5x+5"

Teste criado
TestCase ((isNumber "2.5") @? "isNumber 2.5") TestCase ("5x+5" @=? (simplif "2x+1+3x+4")) TestCase ((simplif "2x+1+3x+4") @?= "5x+5")

Tabela 4.7

Exemplos de construes de testes com operadores

Sobrecarga de funes de testes


Outra forma de construir testes utilizar a funo com sobrecarga

test

da classe de tipo

Testable:

class Testable t where test :: t -> Test instance Testable Test where test = id instance (Assertable t) => Testable (IO t) where test = TestCase . assert instance (Testable t) => Testable [t] where test = TestList . map test
A funo test constri um teste tanto atravs de um valor de tipo Assertion (utilizando a funo TestCase), uma lista de testes (utilizando TestList) ou um valor de tipo Test (no fazendo alteraes).

34

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 5

Arquitectura do ambiente de testes


5.1 Componentes da arquitectura do ambiente de testes
Para o ambiente de testes desenhou-se uma arquitectura com quatro componentes, esquematizada na gura 5.1. O objectivo disponibilizar ao programador uma plataforma de testes para programas em Haskell que se adapte a qualquer programa a ser testado. Os casos de teste so especicados atravs de cheiros texto num dialecto XML criado para o efeito. Um componente designado estende a

Testador

(que

framework

HUnit com novas funcionalidades) executa os testes indicados no cheiro e produz

um cheiro de sada em

plain text com os resultados dos casos de teste. O componente Interface serve de intermedirio entre o Testador e a aplicao a testar, evitando que dependam um do outro. Embora o Testador dependa de um Interface, este varia de aplicao para aplicao.

Figura 5.1

Arquitectura do ambiente de testes

Nas seces seguintes descreve-se cada um dos componentes da arquitectura de testes.

35

Testes de Programas em Haskell

Teste e Qualidade de Software

5.2 Framework HUnit


A HUnit uma

framework

de testes unitrios para a linguagem Haskell, desenvolvida em 2002 por

Dean Herington. um componente independente na arquitectura.

5.3 Aplicao a testar


Sendo o ambiente de testes a linguagem Haskell, a aplicao a testar ter que ser codicada nesta linguagem. Embora a aplicao possa ter interaco IO, os testes s podero incidir em funes que no tenham estas interaces. No existem outras restries de especial aplicao a testar, sendo esta uma componente independente na arquitectura.

5.4 Testador
O Testador destina-se a executar uma suite de testes extendendo a cionalidades, nomeadamente:

framework

HUnit com novas fun-

Independncia relativamente aplicao a testar; Incluso de um

parser

XML para HtestML, que permite escrita dos testes em cheiro XML (em

vez de directamente no cdigo), permitindo facilmente a adopo de testes

data driven ;

Resultados da execuo dos testes escritos num cheiro texto (em vez de terminal de sada); Traduo dos resultados para Portugus; Diferenciao de diferentes execues do mesmo conjunto de testes.

5.5 Interface
O Interface associa o Testador Aplicao, de forma a que um no dependa do outro. As suas principais funes so:

Associar funes indicadas no cheiro XML (sob a forma de aplicao a testar;

string ) com as

funes a invocar da

Fornecer instncias da funo

Show

(que apresenta resultados no terminal de sada) de forma a

permitir que funes que manipulem valores diferentes de de teste;

string

possam ser includas nos casos

Para cada aplicao a testar tem que existir um componente Interface associado, pelo que este mdulo depende sempre da aplicao. pode ser sempre diferente. Por esse motivo, o Testador inclu um mdulo Interface que

O Testador invoca a funo

interpretar

do Interface para traduzir os

testes indicados no cheiro XML em funes presentes na aplicao a testar. este mecanismo que permite que Testador no dependa directamente da aplicao e sim de uma Interface que conserva o seu nome mas varia conforme a aplicao.

36

Testes de Programas em Haskell

Teste e Qualidade de Software

5.6 Ficheiro de testes e dialecto HtestML


Para a denio dos casos de teste e a sua organizao em hierarquias de teste, foi concebido um dialecto XML, designado de HtestML (

Haskell Test Markup Language ).

A natureza hierrquica das rvores de

teste torna o formato XML adequado para a sua representao. O Testador solicita um cheiro XML e converte-o numa lista de testes em memria de acordo com a hierarquia indicada pela profundidade dos elementos no documento. Com este formato possvel indicar:

Nomes para testes Descrio opcional para casos de teste Funo a executar em casos de teste Valor a avaliar na funo indicada Valor a esperar na avaliao da funo indicada

Para formalizar a especicao do formato, indica-se a descrio atravs de um DTD (

Document

Type Denition ) do dialecto HtestML:


<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT TESTE (NOME,(CASO_TESTE | TESTE)+)> <!ELEMENT NOME(#PCDATA)> <!ELEMENT CASO_TESTE (DESCRICAO+, FUNCAO, AVALIAR, ESPERAR)> <!ELEMENT DESCRICAO (#PCDATA)> <!ELEMENT FUNCAO(#PCDATA)> <!ELEMENT AVALIAR (#PCDATA)> <!ELEMENT ESPERAR(#PCDATA)>
Um formato mais completo para indicar a sintaxe do dialecto o XSD (

XML Schema Denition ),

que mais rico em termos descrio de ocorrncias e tipos de dados de elementos. Apresenta-se a seguir o

Schema

de descrio do dialecto HtestML:

<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="TESTE"> <xs:complexType> <xs:sequence> <xs:element name="NOME" type="xs:string"/> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element ref="CASO_TESTE"/> <xs:element ref="TESTE"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="CASO_TESTE"> <xs:complexType> <xs:sequence> <xs:element name="DESCRICAO" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="FUNCAO" type="xs:string" minOccurs="1" maxOccurs="1"/> <xs:element name="AVALIAR" type="xs:string" minOccurs="1" maxOccurs="1"/> <xs:element name="ESPERAR" type="xs:string" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

37

Testes de Programas em Haskell

Teste e Qualidade de Software

Apresenta-se a seguir o documento que representa a rvore de testes referente gura 4.2.

<?xml version="1.0" encoding="UTF-8"?> <TESTE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="HtestML.xsd"> <NOME>Polinmios</NOME> <TESTE> <NOME>Somas</NOME> <CASO_TESTE> <DESCRICAO>Nmeros</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>2+7</AVALIAR> <ESPERAR>9</ESPERAR> </CASO_TESTE> <CASO_TESTE> <DESCRICAO>Monmios</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>2x+7x</AVALIAR> <ESPERAR>9x</ESPERAR> </CASO_TESTE> <CASO_TESTE> <DESCRICAO>Polinmio</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>3x^2+9x^2+3x+5+x</AVALIAR> <ESPERAR>12x^2+4x+5</ESPERAR> </CASO_TESTE> </TESTE> <TESTE> <NOME>Produtos</NOME> <CASO_TESTE> <DESCRICAO>Nmeros</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>2*7</AVALIAR> <ESPERAR>15</ESPERAR> </CASO_TESTE> <CASO_TESTE> <DESCRICAO>Monmios</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>2x*7x</AVALIAR> <ESPERAR>14x^2</ESPERAR> </CASO_TESTE> <CASO_TESTE> <DESCRICAO>Polinmio</DESCRICAO> <FUNCAO>simplif</FUNCAO> <AVALIAR>3x^2*9x^2*3x*5*x</AVALIAR> <ESPERAR>405x^6</ESPERAR> </CASO_TESTE> </TESTE> <CASO_TESTE> <FUNCAO>simplif</FUNCAO> <AVALIAR>2^3</AVALIAR> <ESPERAR>8</ESPERAR> </CASO_TESTE> </TESTE>

5.7 Ficheiro de resultados


O Testador envia os resultados da execuo dos testes indicados no documento HtestML para um cheiro texto (

plain text ).

O cheiro de resultados indica o cheiro de origem dos testes em HtestML, a

data ocorreu a execuo e o n

o de vezes que esse cheiro foi executado nessa data (identicando assim a

execuo em causa). O prprio nome que o Testador atribui ao cheiro segue um formato que permite perceber estas atributos.

38

Testes de Programas em Haskell

Teste e Qualidade de Software

O formato adoptado para o nome dos cheiros o seguinte:

{ficheiro_origem}_{data}_{no execucao}.txt
A parte restante do cheiro consiste na apresentao do resultado da execuo de cada caso de teste. Este cheiro apresenta uma verso modicada do as mensagens traduzidas para Portugus. Tal como na

output produzido pela framework HUnit, com framework, para os casos bem sucedidos so
ESPERADO,
e o valor obtido

apresentadas somente os quatro contadores, no entanto, para os casos que apresentem falhas, indicada a funo, obtido do elemento

FUNCAO,

o valor esperado, obtido do elemento

ao aplicar funo o valor indicado no elemento

AVALIAR.

A indicao do caminho do caso de teste foi profundamente alterada. O caminho especicado de acordo com o standard de XML, como o

XPath do W3C, que identica elementos num documento XML. Alguns editores XML Spy, aceitam expresses XPath e navegam directamente para o elemento XML

identicado. Desta forma possvel facilmente identicar no documento que contem os testes, o caso de teste que falhou

39

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 6

Concepo dos casos de teste


6.1 Abordagem para a concepo dos casos de teste
A motivao para a concepo de casos de teste e a sua posterior execuo tem dois objectivos. Por um lado necessrio vericar se a especicao cumprida, atravs da deteco de

defeitos.

Os defeitos

ocorrem quando uma funcionalidade no tem o funcionamento esperado. Por outro lado, necessrio medir a

qualidade dos resultados

obtidos pela aplicao. Um resultado, apesar de correcto, pode ter

vrios nveis de qualidade. Este aspecto particularmente mensurvel na aplicao em teste quando efectua simplicaes de expresses. Os casos de teste so concebidos com base na especicao da aplicao a testar. A especicao expressa num conjunto de regras agrupadas por categorias. Cada regra tem um cdigo, uma descrio e especica o

input

output

esperados de uma forma abstracta.

O tipo de abordagem consiste nos seguintes pontos:

Tratar cada regra (mais precisamente, a gama de valores de entrada especicada na condio) como uma classe de equivalncia

Uma vez que a especicao recursiva, um mesmo caso de teste pode cobrir vrias regras Encontrar um conjunto mnimo de casos de teste que cubram todas as regras Quando uma regra testada mais do que uma vez, usar valores diferentes

Nas seces seguintes apresentam-se as regras de especicao e os casos de testes concebidos para as contemplar.

6.2 Regras de especicao


As regras de especicao da aplicao em teste  Aplicao de simplicao e derivao de expresses matemticas  so apresentadas em trs categorias, que correspondem s funcionalidades a testar:

Converso de formatos Simplicao de expresses Derivao de expresses

40

Testes de Programas em Haskell

Teste e Qualidade de Software

6.2.1 Converso de formatos


A converso de formatos engloba os seguintes duas categorias de converso. As converses entre expresses no formato interno e externo e as converses entre expresses no formato interno e representao em rvore. Ambas as categorias tem conversores nos dois sentidos de converso. Associada converso de expresses do formato interno para o externo est a operao de validao sintctica.

Converso de formato externo para formato interno


Cada regra deste conjunto indica uma transformao que efectuada para a converso de uma expresso originalmente do formato externo (conhecido pelo utilizador) para o formato interno (antes da converso em rvore). As transformaes associadas a cada regra vo sendo efectuadas pela ordem apresentada na tabela 6.1.

Cod.
CVFI01 CVFI02 CVFI03 CVFI04 CVFI05 CVFI06

Descrio
Remoo de espaos Converso de maisculas em minsculas Insero de radical 2 onde implcito Insero de sinal

Formato externo
a +b

Formato interno
a+b sen(a) 2 a 2a 21a 2 + 1 x

Sen(a) a 2a 2a

onde implcito

Insero de factor (-1) onde omitido Insero de sinal antes de cada sinal

21a

Tabela 6.1

Transformao de expresses para o formato interno

As regras CVFI01 e CVFI02 so sempre efectuadas para qualquer expresso. As regras restantes, pelo contrrio, s so efectuadas perante a presena de operadores especcos.

Validao sintctica
No cenrio da converso de formatos efectuada a validao sintctica de expresses no formato interno. A validao sintctica descrita por um conjunto de regras s quais correspondem vericaes efectuadas pela ordem apresentada na tabela 6.2:

Cod.
VSIN01 VSIN02 VSIN03 VSIN04 VSIN05 VSIN06

Descrio
Expresso no indicada Smbolo invlido Parntesis no fechados Expresso invlida Funo desconhecida Elemento desconhecido

Causa
Ausncia de caracteres Presena de caracteres no denidos na gramtica Parntesis abertos diferentes de parntesis fechados Sequncia gramatical no denida Funo no denida na gramtica Varivel no denida na gramtica

Expresso

2:4 2x((x + 1) 2 + 5 sec(x) 2t + 1

Tabela 6.2

Vericaes efectuadas para validao sintctica da expresso

41

Testes de Programas em Haskell

Teste e Qualidade de Software

Converso de formato interno para formato externo


As regras desta seco dizem respeito s transformaes inversas s apresentadas na tabela 6.1, um vez que se referem ao processo inverso. As regras correspondentes a essas transformaes apresentam-se na tabela 6.3:

Cod.
CVFE01 CVFE02 CVFE03 CVFE04

Descrio
Remoo do radical 2 onde implcito Remoo do sinal

Formato interno
2 a

Formato externo
a

onde implcito

2a 21a 2 + 1 x

2a 2a 21a

Insero de factor (-1) onde omitido Insero de sinal

antes de cada sinal

Tabela 6.3

Transformao de expresses para o formato externo

Construo de rvore a partir de expresso


A segunda categoria de converses so as que envolvem a transformao de expresses do formato interno para a sua representao em rvore e vice-versa. A aplicao efectua a anlise lxica dos

constituintes de uma expresso formando uma representao em rvore (

parse tree )

cujos ns so ele-

mentos. Cada elemento um tuplo formado por quatro atributos, de acordo com a seguinte organizao:

Elemento (Tipo, Coeficiente, Expoente, [sub-elementos])


Cada elemento tem um tipo (valor alfanumrico), um coeciente e expoente (valores numricos) e uma lista de sub-elementos (que pode ser vazia). A tabela 6.4 mostra os atributos dos diferentes tipos de elementos considerados pela aplicao:

Cod.
REPA01 REPA02 REPA03 REPA04 REPA05 REPA06

Descrio
Constante Varivel Adio Multiplicao Potenciao Funo

Tipo
k x + nome

Coeciente
valor 1 1 1 1 1

Expoente
0 1 1 1 1 1

Sub-elementos
  Parcelas Factores Base e Expoente Argumento

Tabela 6.4

Construo da representao em rvore de uma expresso

Para construir a rvore, necessrio separar os operandos dos operadores na expresso. Para esse efeito, detectada a operao de menor precedncia e as posies em ocorre na expresso. A presena de parntesis implica que a expresso que encapsulam no considerada para a deteco da operao de menor prioridade da expresso exterior.

42

Testes de Programas em Haskell

Teste e Qualidade de Software

6.2.2 Simplicao de Expresses


A funcionalidade de simplicao de expresses constitui um dos objectivos da aplicao, sendo efectuada pelo bloco funcional designado por

Simplicador.

Operadores algbricos bsicas


O primeiro grupos de regras de especicao do processo de simplicao so a descrio das operaes algbricas bsicas suportadas, apresentadas na tabela 6.5:

Cod.
OPER01 OPER01 OPER01

Operao
Adio Multiplicao Potenciao

Descrio
c c c
o resultado da soma de

Expresso
a
a com

b b

c=a+b c=ab c = ab

o resultado do produto de o resultado de elevar

com

Tabela 6.5

Operaes algbricas bsicas tratadas pela aplicao

Propriedades dos operadores algbricos


Para estas operaes devem vericar as propriedades dos operadores algbricos, apresentadas na tabela 6.6 e que tambm denem outros operadores:

Cod.
PALG01 PALG02 PALG03 PALG04 PALG05 PALG06 PALG07 PALG08 PALG09 PALG10 PALG11 PALG12 PALG13 PALG14 PALG15 PALG16 PALG17

Descrio
Elemento neutro da adio Elemento inverso da adio Comutatividade da adio Associatividade da adio Denio de subtraco Elemento neutro da multiplicao Elemento absorvente da multiplicao Elemento inverso da multiplicao Comutatividade da multiplicao Associatividade da multiplicao Denio de diviso Soma de expoentes Produto de bases Produto de expoentes Expoente inverso Diferena de expoentes Denio de radiciao

Propriedade
a+0=a a + (a) = 0 a+b=b+a (a + b) + c = a + (b + c) a b = a + (b) a1=a a0=0 a
1 a

=1

ab=ba (a b) c = a (b c) a ac = a(b+c) ac bc = (a + b)c (ab )c = abc ab =


1 ab
b

a b = b

a (1 b)

a abc = a c b c (c b a =a )

Tabela 6.6

Propriedades dos operadores algbricos

43

Testes de Programas em Haskell

Teste e Qualidade de Software

Funes matemticas
Finalmente, o processo de simplicao deve tratar algumas funes contempladas pela aplicao. Quando o argumento for numrico, deve ser substitudo pelo valor correspondente aplicao da funo, caso contrrio, deve ser simplicado o mais possvel. A tabela 6.7 apresenta as funes contempladas pela aplicao, agrupadas por categorias. A descrio comum a todas as regras, sendo aplicao da funo ao seu argumento

b o resultado da

a,

em que

uma qualquer expresso. de particular interesse

a identicao do domnio de cada funo, porque essa informao importante para uma das regras de validao semntica.

Cod.
FUNC01 FUNC02 FUNC03 FUNC04 FUNC05 FUNC06 FUNC07 FUNC08

Funo
Seno Co-seno Tangente Arco seno Arco co-seno Arco tangente Logartmica Exponencial

Expresso
b = sen(a) b = cos(a) b = tg (a) b = arcsen(a) b = arccos(a) b = arctg (a) b = log (a) b = exp(a)

Domnio (D)
aR aR aR:a= a [1, 1] a [0, ] aR a R+ aR
2

+ k, k Z

Tabela 6.7 Validao semntica

Funes matemticas tratadas pela aplicao

Em simultneo com o processo de simplicao de uma expresso efectuada a sua validao semntica, onde se vericam as regras apresentadas na tabela 6.8. Todas as regras se referem a violaes de

domnio das expresses, no entanto, separam-se em trs regras diferentes para identicar os casos de maior destaque.

Cod.
VSEM01 VSEM02 VSEM03

Descrio
Argumento invlido Diviso por zero Radicando negativo

Causa
Violao do domnio de uma funo da tabela 6.7 Denominador de fraco simplica para zero Radicando negativo em raiz de ndice par

Expresso
a /D
a b,b = 0 b a, a < 0 b
par

Tabela 6.8

Vericaes efectuadas para validao semntica

6.2.3 Derivao de Expresses


A funcionalidade de derivao de expresses constitui o outro objectivo fundamental da aplicao em teste, sendo efectuada pelo bloco funcional designado por

Derivador.

As regras de especicao cor-

respondem s regras de derivao suportadas pela aplicao e contemplam constantes, variveis, as operaes da tabela 6.5 e as funes da tabela 6.7.

44

Testes de Programas em Haskell

Teste e Qualidade de Software

A tabela 6.9 apresenta as regras de derivao suportadas pela aplicao. seguinte:

A notao utilizada a

y y a a

representa a expresso a derivar representa a expresso referente ao clculo da derivada de e e

b b

representam sub-expresses em representam as derivadas de

y
e

respectivamente

Cod.
RDEV01 RDEV02 RDEV03 RDEV04 RDEV05 RDEV06 RDEV07 RDEV08 RDEV09 RDEV10 RDEV11 RDEV12 RDEV13

Descrio
Constantes Variveis Adio Multiplicao Potenciao Funo seno Funo co-seno Funo tangente Funo arco seno Funo arco co-seno Funo arco tangente Funo exponencial Funo logaritmo

Expresso
y=k y=x y =a+b y = ab y=a
b

Derivada
y =0 y =1 y =a +b y = a b + ab y = bab1 a + b ab log (a) y = a cos(a) y = a sen(a) y = 1 + tg (a)2 y = y = y = y =
a 1a a 1 a a 1+a a a a

y = sen(a) y = cos(a) y = tg (a) y = arcsen(a) y = arccos(a) y = arctg (a) y = ea y = log (a)

y =ae

Tabela 6.9

Regras de derivao de expresses

6.3 Casos de Teste


A partir das regras de especicao da aplicao em teste so denidos um conjunto de casos de teste. Os casos de teste devem cobrir todas as regras tendo como objectivo, por um lado, vericar a conformidade da aplicao com a especicao e por outro, medir a qualidade dos resultados obtidos. Os casos de teste so denidos por categorias, seguindo uma estrutura semelhante aos grupos de regras denidos na seco anterior. Por esse motivo, os testes esto agrupados em trs grandes grupos: testes de converso de formatos, testes de simplicao e testes de derivao. Os testes de converso de formatos incidem na vericao das regras apresentadas nas tabelas 6.1, 6.2, 6.3 e 6.4. Os testes de simplicao de expresses incidem na vericao das regras apresentadas nas tabelas 6.5, 6.6, 6.7 e 6.8 e tambm na medio da qualidade dos resultados obtidos. Os testes de derivao de expresses incidem na vericao das regras apresentadas na tabela 6.9 e tal como no grupo anterior, na medio da qualidade dos resultados obtidos.

45

Testes de Programas em Haskell

Teste e Qualidade de Software

6.3.1 Converso de formatos


Testes de converso entre o formato externo e o formato interno
Os teste de converso de formato externo para formato interno envolvem a execuo da funo da interface de testes sintctica. Como

ivalidar_sint,

que no tem interaco IO, efectuando a converso e a validao

input

indica-se a expresso no formato externo e como

output

obtm-se a expresso

correspondente no formato interno. 1.

Testes de integridade de valores numricos


A integridade de valores numricos em expresses um aspecto no contemplado nas regras de especicao. No h informao sobre a gama de valores admitida para as constantes, nem Este grupo de testes tem como objectivo vericar

para o nmero mximo de casas decimais.

se a converso para o formato interno no afecta constantes, e em simultneo, se a aplicao consegue tratar gamas de valores elevadas, bem como um grande nmero de casas decimais. No estando denida na gramtica das expresses a notao cientica para exprimir valores de gamas elevadas, nos casos de teste necessrio a indicar estes valores em notao normal. Note-se que nesta converso no ocorre qualquer simplicao de valores, pelo que de esperar que os valores se mantenham com o mesmo aspecto, ainda que possam conter dgitos redundantes.

No
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Input
0 0000 1 0001 123456 10000000000 -0 -0000 -1 -0001 -123456 -10000000000 0.0 0000.0000 1.5 456.7890123 -0.0 -1000.0000 -1.5 -456.7890123

Output
0 0000 1 0001 123456 10000000000 -0 -0000 -1 -0001 -123456 -10000000000 0.0 0000.0000 1.5 456.7890123 -0.0 -1000.0000 -1.5 -456.7890123

Descrio
Zero sem sinal com um digito Zero sem sinal com dgitos redundantes Valor inteiro positivo com um digito Valor inteiro positivo com dgitos redundantes Valor inteiro positivo com vrios dgitos Valor inteiro positivo elevado Zero com sinal negativo com um digito Zero com sinal negativo com dgitos redundantes Valor inteiro negativo com um digito Valor inteiro negativo com dgitos redundantes Valor inteiro negativo com vrios dgitos Valor inteiro negativo elevado Zero sem sinal com um digito com uma casa decimal Zero sem sinal com dgitos redundantes e casas decimais Valor inteiro positivo com um digito e uma casa decimal Valor inteiro positivo com casas decimais Zero com sinal negativo com uma casa decimal Valor inteiro negativo com casas decimais redundantes Valor inteiro negativo com um digito com uma casa decimal Valor inteiro negativo com casas decimais

Tabela 6.10

Testes de integridade de valores numricos inteiros

46

Testes de Programas em Haskell

Teste e Qualidade de Software

2.

Testes de transformao de expresses para o formato interno


Este grupo de testes verica uma a uma as regras da tabela 6.1 isoladas e depois combinadas numa s expresso.

No
1 2 3 4 5 6 7

Input
X +1 + SEN (Cos(x))

Output
x + 1 + sen(cos(x)) 2|(x + 2) + 3|x 2 x + x sen(x) x (x + 1) (x + 2) 2 + 1 x + 5 + 3 1 (x + 1) 2 2|(x + 1 (x 5 cos(x)))

Cobre regra CVFI


01 e 02 03 04 04 05 e 06 05 e 06 01 a 06

|(x + 2) + 3|x 2x + xsen(x) x(x + 1)(x + 2) 2x+53 (x + 1) 2 | (x (X 5cos(x)))

Tabela 6.11
3.

Testes de converso de formato externo para o formato interno

Testes de validao sintctica


Este grupo de testes verica a correcta deteco dos erros de validao sintctica apresentados na tabela 6.2 isolados. No faz muito sentido um caso de teste que combine os vrios erros porque a validao, perante um erro, j no detecta os seguintes, acusando somente o primeiro.

No
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Input

Output
ERRO: Funcao nao indicada

Cobre regra VSIN


01 02 02 02 03 03 03 04 04 04 05 05 06 06 06

2?3 cos(2 \ 4) y = 2x + 3 ((x + 1)(x + 2) + 3 (x + 1))(x + 2) + 3 sen(x + 3 +1 1 2 + 5 2 + sec(x) sen(cotg (x)) 2 + sec + x sen(t) 2x + 3 equation

ERRO: Simbolo invalido ERRO: Simbolo invalido ERRO: Simbolo invalido ERRO: Parenteses nao fechados correctamente ERRO: Parenteses nao fechados correctamente ERRO: Parenteses nao fechados correctamente ERRO: Expressao invalida ERRO: Expressao invalida ERRO: Expressao invalida ERRO: Funcao 'sec' desconhecida ERRO: Funcao 'cotg' desconhecida ERRO: Elemento 'sec' desconhecido ERRO: Elemento 't' desconhecido ERRO: Elemento 'equation' desconhecido

Tabela 6.12
4.

Testes de converso de validao sintctica

Testes de transformao de expresses para o formato externo


Este grupo de testes verica as regras da tabela 6.1 isoladas, mas na direco contrria. Excluindo as duas primeiras que no tm contrapartida para a transformao inversa, vericam-se

47

Testes de Programas em Haskell

Teste e Qualidade de Software

a recuperao do formato externo a partir de uma expresso no formato interno.

No
1 2 3 4 5 6

Input
2|(x + 2) + 3|x 2 x + x sen(x) x (x + 1) (x + 2) 2 + 1 x + 5 + 3 1 (x + 1) 2 2|(x + 1 (x 5 cos(x)))

Output
|(x + 2) + 3|x 2x + xsen(x) x(x + 1)(x + 2) 2x+53 (x + 1) 2 | (x (X 5cos(x)))

Cobre regra CVFI


03 04 04 05 e 06 05 e 06 01 a 06

Tabela 6.13

Testes de converso de formato interno para o formato externo

Testes de converso entre o formato interno e a representao em rvore


Os testes de converso de formato interno para representao em rvore envolvem a execuo da funo da interface

iespandir.

A funo

espandir

efectua na aplicao a converso de uma expresso em Esta funo levantou o problema da apresentao dos

string

para a sua representao em rvore.

resultados, j que o tipo de dados de sada

Expressao.

Para tornar o resultado de sada como uma

string e assim possibilitar a sua utilizao na arquitectura de testes denida, foi necessrio incluir na interface de testes um instncia da funo

show para o tipo de dados Expressao. A funo iespandir da interface por sua vez invoca a funo show sobre a funo espandir o que possibilita a apresentao
do resultado como uma Como

string. output
obtm-se a lista correspondente

input

indica-se a expresso no formato interno e como

representao em rvore. 1.

Testes bsicos de representao em rvore


Os primeiros testes a efectuar cobrem de uma forma bsica as regras de criao de elementos que constituem ns da representao em rvore da expresso.

No
1 2 3 4 5 6

Input
3.5 x 2+x 2x 2x cos(x + 2)

Output
(k, 3.5, 0.0, []) (x, 1.0, 1.0, []) (+, 1.0, 1.0, [(k, 2.0, 0.0, [])(x, 1.0, 1.0, [])]) (, 1.0, 1.0, [(k, 2.0, 0.0, [])(x, 1.0, 1.0, [])]) (, 1.0, 1.0, [(k, 2.0, 0.0, [])(x, 1.0, 1.0, [])]) (cos, 1.0, 1.0, [(+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 2.0, 0.0, [])])])

Cobre regra REPA


01 02 01, 02 e 03 01, 02 e 04 01, 02 e 05 01, 02, 03 e 06

Tabela 6.14
2.

Testes bsicos de converso de expresses no formato interno a representao em rvore

Testes genricos de representao em rvore


O grupo de testes na tabela 6.15 procuram cobrir vrias regras numa mesma expresso de forma a aferir a complexidade da rvore gerada.

48

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2

Input/Output
2 + 3 + 4 + 5 (+, 1.0, 1.0, [(k, 2.0, 0.0, [])(k, 3.0, 0.0, [])(k, 4.0, 0.0, [])(k, 5.0, 0.0, [])]) 2 3 + 4 x + 5 (+, 1.0, 1.0, [(, 1.0, 1.0, [(k, 2.0, 0.0, [])(k, 3.0, 0.0, [])]) (, 1.0, 1.0, [(k, 4.0, 0.0, [])(x, 1.0, 1.0, [])])(k, 5.0, 0.0, [])])

4x2+3x+1 (+, 1.0, 1.0, [(, 1.0, 1.0, [(k, 4.0, 0.0, [])(, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 2.0, 0.0, [])])]) (, 1.0, 1.0, [(k, 3.0, 0.0, [])(x, 1.0, 1.0, [])])(k, 1.0, 0.0, [])])

4 5 6 7 8 9 10

(x + 2.5) 3.2 (, 1.0, 1.0, [(+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 2.5, 0.0, [])])(k, 3.2, 0.0, [])]) 2 x (3 + x + 5) (, 1.0, 1.0, [(k, 2.0, 0.0, [])(x, 1.0, 1.0, [])(+, 1.0, 1.0, [(k, 3.0, 0.0, [])(x, 1.0, 1.0, [])(k, 5.0, 0.0, [])])]) (x + 1) (x + 2) (, 1.0, 1.0, [(+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 1.0, 0.0, [])])(+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 2.0, 0.0, [])])]) ((x + 1)) (+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 1.0, 0.0, [])]) ((((x + 1)))) (+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 1.0, 0.0, [])]) ((((x + 1)) + 2)) (+, 1.0, 1.0, [(+, 1.0, 1.0, [(x, 1.0, 1.0, [])(k, 1.0, 0.0, [])])(k, 2.0, 0.0, [])]) tg (log (2 x) + sen(x)) (tg, 1.0, 1.0, [(+, 1.0, 1.0, [(log, 1.0, 1.0, [(, 1.0, 1.0, [(k, 2.0, 0.0, [])(x, 1.0, 1.0, [])])]) (sen, 1.0, 1.0, [(x, 1.0, 1.0, [])])])])

Tabela 6.15 Testes genricos de converso de expresses no formato interno a representao em rvore

6.3.2 Simplicao de Expresses


Os testes de simplicao de expresses sero efectuados sob um ponto de vista de testes de sistema. Os

inputs

sero expresses no formato externo, que sero convertidas para o formato interno e poste-

riormente para sua representao em rvore. Nessa representao, aplicada a funo de simplicao que reduz a rvore o mais possvel. A rvore convertida na expresso no formato interno e de seguida no formato externo, que sero os

outputs.

Os testes podiam incidir somente na componente de simplicao, no entanto, tal obrigaria a trabalhar com representaes em rvore que so de escrita extensa e pouco cmoda, no trazendo qualquer mais-valia para os objectivos destes testes. Estes so por um lado, avaliar a correco da expresso

simplicada e por outro medir a qualidade da simplicao, ou seja, se de facto a expresso resultante a mais simples possvel ou se seria possvel efectuar mais simplicaes. Os testes de simplicao incluem vericao das regras e propriedades dos operadores algbricos bsicas, das funes denidas, regras de validao semntica, requisitos bsicos de simplicao e por m teste de qualidade.

49

Testes de Programas em Haskell

Teste e Qualidade de Software

Testes de simplicao de operaes algbricas bsicas


O grupo de testes da tabela 6.16 destina-se a vericar expresses que envolvam clculo numrico de constantes em diferentes contextos (como constantes e coecientes), nas trs operaes algbricas bsicas (adio, multiplicao e potenciao).

No
1 2 3 4 5 6

Input
1.1 + 2.3 + 4 1.1 2.3 4 1.1 2.3 4 35+23+1 3x 2 + 2x + 4 + 5x 2 + 3x + 2 sen(x) + 4 + 3x + 2sen(x) + 2 + x

Output
7.4 10.12 14.399156128283 24 8x 2 + 5x + 6 3sen(x) + 6 + 4x

Cobre regra OPER


01 02 03 01, 02 e 03 01, 02 e 03 01, 02 e 03

Tabela 6.16

Testes de operaes algbricas bsicas

Testes de vericao de propriedades do operadores algbricos


O grupo de testes das tabelas 6.17 e 6.18 permitem vericar as propriedades dos operadores algbricos apresentadas nas regras de especicao da tabela 6.6.

No
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Input
5+0+3 5 + (5) 2+x+3 x+2+3 (2 + x) + 3 2 + (x + 3) 23 2 + (3) 513 503 3x x3 (2x) 3 2(3x) 2/5

Output
8 0 x+5 x+5 x+5 x+5 1 1 15 0 3x 3x 6x 6x 0.4

Cobre regra PALG


01 02 03 03 04 04 05 05 06 07 09 09 10 10 11

Tabela 6.17

Testes das propriedades dos operadores algbricos

50

Testes de Programas em Haskell

Teste e Qualidade de Software

No
16 17 18 19 20 21 22 23 24 25 26 27 28

Input
2 0.2 5 (1/5) 3233 3 (2 + 3) 223 2 (2 3) (2 2) 3 2 (3) 1/(2 3) 3 (5 2) 3 5/3 2 |(3 4) 3 (4/2)

Output
0.4 1 243 243 256 256 64 0.125 0.125 27 27 9 9

Cobre regra PALG


11 08 12 12 14 14 14 15 15 16 16 17 17

Tabela 6.18

Testes das propriedades dos operadores algbricos

Testes de simplicao de avaliao de funes


O grupo de testes das tabelas 6.19 e 6.20 permitem vericar as situaes fronteira da avaliao das funes trigonomtricas suportadas pela aplicao. Algumas dessas situaes so valores conhecidos

que permitem facilmente determinar se as funes so correctamente avaliadas.

No
1 2 3 4 5 6 7 8 9 10 11

Input
sen(0) sen(arcsen(1) 2/3) sen(arcsen(1)) cos(0) cos(arcsen(1)/6) cos(arcsen(1)) tg (0) tg (arcsen(1) 2/3) arcsen(0) arcsen(1) arccos(0)

Output
0 0.866025403784439 1 1 0.965925826289068 0 0 1.73205080756888 0 1.5707963267949 1.5707963267949

Cobre regra FUNC


01 01, 04 01, 04 02 02, 04 02, 04 03 03, 04 04 04 05

Tabela 6.19 Testes de validao semntica

Testes de simplicao de avaliao de funes

O grupo de testes das tabelas 6.21 destinam-se a vericar as regras de validao semntica atravs de expresses que contenham violaes do domnio das funes envolvidas. As funes so as indicadas

51

Testes de Programas em Haskell

Teste e Qualidade de Software

No
12 13 14 15 16 17 18 19

Input
arccos(1) arctg (0) arctg (1) e(0) e(1) log (1) log (e(1)) e(log (1))

Output
0 0 0.785398163397448 1 2.71828182845905 0 1 1

Cobre regra FUNC


05 06 06 08 08 07 07, 08 07, 08

Tabela 6.20

Testes de simplicao de avaliao de funes

na 6.7 que inclu uma coluna para a gama de valores admitidos no domnio. Nos testes seguintes, a violaes de domnio explicita em alguns casos e implcita noutros (advm de simplicao de valores).

No
1 2 3 4 5 6 7 8

Input
tg (arccos(1)/2) arcsen(2) arccos(2 arccos(1)) log (0) (5 x)/(3 + 8 5) 3/(x x) |(1) 4|(2)

Output
ERRO: Argumento invalido em 'tg' ERRO: Argumento invalido em 'arcsen' ERRO: Argumento invalido em 'arccos' ERRO: Argumento invalido em 'log' ERRO: Divisao por zero ERRO: Divisao por zero ERRO: Radicando negativo em raiz de radical par ERRO: Radicando negativo em raiz de radical par

Cobre regra VSEM


01 01 01 01 02 02 03 03

Tabela 6.21 Testes de qualidade de simplicao

Testes de validao semntica

O ltimo conjunto de testes no mbito da simplicao visa averiguar a qualidade da simplicao. Para estes testes, assume-se que a expresso em causa ser simplicada sem erros. Nestes testes no so indicadas as regras de especicao cobertas, uma vez que no esse o foco de anlise. O foco da anlise vira-se para a capacidade da aplicao em obter expresses o mais simples possvel. Assim os resultados destes, indicam no se a expresso est correcta, mas se est efectivamente na sua forma mais simples. 1. Simplicao de Somas As expresses que envolvem somas foram agrupadas em dois conjuntos: o das somas simplicveis (tabela 6.22) e o das somas no simplicveis (tabela 6.23). 2. Simplicao de Diferenas Neste conjunto de testes (tabela 6.24) pretende-se avaliar se uma expresso simplica correctamente para o valor zero atravs de diferenas de valores simtricos.

52

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2 3 4 5

Input
x 2 + 3x + 4 + 5x 2 + 4x + 6 4 + 3x + x 2 + 5x 2 + 4x + 6 (x 2 + 3x + 4) + (5x 2 + 4x + 6) (x 2 + 3x + 4) + 2(5x 2 + 4x + 6) sen(x) + sen(x + 1) + sen(x) + sen(x + 1)

Output
6x 2 + 7x + 10 6x 2 + 7x + 10 6x 2 + 7x + 10 x 2 + 3x + 4 + 2(5x 2 + 4x + 6) 2sen(x) + 2sen(x + 1)

Tabela 6.22
No
1 2 3 4 5 6 7 8 9

Testes de somas simplicveis

Input
x 2 + 3x + 4 4 + 3x + x 2 (x 2 + 3x) + 4 x 2 + (3x + 4) (x 2 + 3x + 4) sen(x) + cos(x) sen(x) + sen(x) 2 sen(x 2) + sen(x) sen(x) + (x + 1)

Output
x 2 + 3x + 4 x 2 + 3x + 4 x 2 + 3x + 4 x 2 + 3x + 4 x 2 + 3x + 4 sen(x) + cos(x) sen(x) + sen(x) 2 sen(x 2) + sen(x) sen(x) + x + 1

Tabela 6.23
3. Simplicao de Produtos

Testes de somas no simplicveis

As expresses que envolvem produtos foram agrupadas em dois conjuntos: o dos produtos simplicveis (tabela 6.25) e o dos produtos no simplicveis (tabela 6.26). 4. Simplicao de Divises Neste conjunto de testes (tabela 6.27) pretende-se avaliar se uma expresso simplica correctamente para o valor unitrio ou se elimina factores neutros. 5. Simplicao de Potncias As expresses que envolvem potncias foram agrupadas em dois conjuntos: o das potncias simplicveis (tabela 6.28) e o das potncias no simplicveis (tabela 6.29).

6.3.3 Derivao de Expresses


Os testes de derivao de expresses so, semelhana dos testes de simplicao, considerados testes de sistema. A sua execuo efectuada atravs da funo

iderivar

que sequncia todo o processo

de derivao com as simplicaes envolvidas. Num primeiro grupo de testes so vericadas as regras de derivao, sendo ento efectuados testes com a composio de vrias regras em expresses que do origem a derivadas progressivamente mais complexas.

53

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2 3 4 5 6 7

Input
(x + 1) x 1 (x + 1) (x + 1) (x + 1) 2 (x + 1) 2 x 2 + 3x + 4 5x 2 4x 6 + 4x 2 + x + 2 sen(x) + 2sen(x) 3sen(x) sen(x 2) sen(x 2) sen(x) 2 sen(x) 2

Output
0 0 0 0 0 0 0
Testes de diferenas

Tabela 6.24
No
1 2 3 4 5 6

Input
2xxx x(x + 1)(x + 1)(x + 2) (x + 1)x(x + 1)(x + 2) (x + 1) 2(x + 2)(x + 1) 3 sen(x)cos(x)sen(x) sen(x)x cos(x)sen(x) 2

Output
2x 3 (x + 1) 2x(x + 2) (x + 1) 2x(x + 2) (x + 2)((x + 1) 5) sen(x) 2cos(x) sen(x) 3 x cos(x)

Tabela 6.25 Regras de derivao

Testes de produtos simplicveis

O grupo de testes da tabela 6.30 pretende vericar as regras de derivao apresentadas na tabela 6.9.

Composio de regras de derivao em expresses


O grupo de testes da tabela 6.31 pretende vericar o trabalho do processo de derivao e simplicao na produo de uma expresso. Os resultados a obter destes testes merecem uma anlise crtica pois no so passveis de poderem ser facilmente classicados como correctos ou errados. As expresses so simplicadas, de seguida derivadas e por m a prpria derivada tambm simplicada. Basta que um termo numa expresso seja simplicado de forma diferente da esperada para que o teste respondente falhe, contudo tal no implica que a expresso no tenha sido correctamente simplicada.

54

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2 3 4 5

Input
x(x + 1) x(x + 1)(x + 3)(x + 2) x(x + 1)(x + 2)(x + 3) sen(x + 1)cos(x)sen(x) sen(x)sen(x 2)

Output
x(x + 1) x(x + 1)(x + 3)(x + 2) x(x + 1)(x + 2)(x + 3) sen(x + 1)cos(x)sen(x) sen(x)sen(x 2)

Tabela 6.26
No
1 2 3 4 5 6

Testes de produtos no simplicveis

Input
x(1/x) x(x + 1)/x (x + 1)x/x (x + 1)(x + 2)/(x + 1) (x + 2)(x + 1)/(x + 1) ((x + 1)(x + 2))/(x + 1)

Output
1 x+1 x+1 x+2 x+2 x+2

Tabela 6.27
No
1 2 3 4 5 6

Testes de divises

Input
x2x3 x (x + 1) + x (x + 1) x (x 2) x (x + 1 1) x8+x8 x23+x8

Output
x5 2x (x + 1) xx2 xx 2x 8 2x 8

Tabela 6.28
No
1 2 3 4

Testes de potncias simplicveis

Input
x (x + 1) (x + 1) x x sen(x) sen(x) x

Output
x (x + 1) (x + 1) x x sen(x) sen(x) x

Tabela 6.29

Testes de potncias no simplicveis

55

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2 3 4 5 6 7 8 9 10 11 12 13

Input
3.5 x 3x x(4x + 5) x (x + 1) sen(x) cos(x) tg (x) arcsen(x) arccos(x) arctg (x) e(x) log (x)

Output
0 1 3 8x + 5 x x(x + 1) + log (x)x (x + 1) cos(x) sen(x) 1 + tg (x) 2 1/|(1 + x 2) 1/((1 + x 2) 0.5) 1/(1 + x 2) e(x) 1/x

Cobre regra RDEV


01 02 04 04 05 06 07 08 09 10 11 12 13
Testes de derivao de expresses

Tabela 6.30

56

Testes de Programas em Haskell

Teste e Qualidade de Software

No
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

Input
3x 2 5x + 1 (x + 3) 5 (x 1)(x 3) (2x 3)(x 2)(x + 3) 1/(x + 3) (3x + 1)/(x 2 8x) ((x 1)/(x + 2)) 2 ((x 2 1)/2x) 3 |(x 3) sen(2x + 1) xsen(x) 2 + 3sen(2x) sen(x 3) 3 cos(3x 2 x) 2cos(1 x) 3 cos(x) + xcos(x 2) 2 sen(x)cos(x) tg (1/(x + 3)) tg (x 2 + 1) 2 cos(x) 2 + tg (xsen(x) 2) tg (|(x 2 + 1)) + tg (cos(x)) arcsen(x 2 + 1) sen(x) 2 + arcsen(x 2) 2 + arcsen(cos(x) 2) 2 arcsen(1/x) + sen(1/x) arccos(x)/x sen(x)arccos(2x) x 3 arccos(|(x 2 1)) arctg (|(x 2 + 1)) 1 + arctg (x) 2 e(x/2) (x 1) 2 e(x) e(arcsen(x)) e(x)sen(x) + e(1/x) log (x 2 + 1) log (sen(x)) log (e(3x) + x 2) cos(log (arctg (x))) (5x) (log (x)) arctg (x) sen(x)
2

Output
6x 5 5(x + 3) 4 2x 4 6x 2 2x 15 1/(x + 3) 2 (3x 2 2x + 8)/(x 2 8x) 2 6(x 1)/((x + 2) 3) 3(x 2 1) 2(x 2 + 1)/(8x 4) 1/(2 |(x 3)) 2cos(2x + 1) sen(x) 2 + 2x 2cos(x) 2 + 6cos(2x) 9cos(x 3)x 2sen(x 3) 2 sen(3x 2 x)(6x 1) 6sen(1 x)cos(1 x) 2 sen(x) 4xsen(x 2)xcos(x 2) + cos(x 2) 2 sen(x) 2 + cos(x) 2 (1 + tg (1/(x + 3)) 2)/((x + 3) 2) 4x(1 + tg (x 2 + 1) 2)tg (x 2 + 1) 2sen(x)cos(x) + (1 + tg (xsen(x) 2) 2)(2xcos(x)sen(x) + sen(x) 2) 2x/|(x 2 + 1) 2x/|(1 (x 2 + 1) 2) 2xsen(x) + (2x)/|(1 x 4) (2sen(2x)arcsen(cos(x) 2))/|(1 cos(x) 4) 1/(x |(x 2 1)) cos(1/x)/(x 2) (x |(1 x 2)arcsen(cos(x) 2)/(x 2 |(1 x 2)) 2sen(x)/|(1 4x 2) + cos(x)arccos(2x) 3x 2arccos(|(x 2 1)) x4 /((|x 2 1)(|2 x 2)) x/(|(x 2 + 1)(x 2 + 2)) 2arctg (x)/(1 + x 2) 0.5e(0.5x) ((x 1) 2)e(x) + 2(x 1)e(x) e(arcsen(x))/|(1 x 2) e(x)cos(x) + e(x)sen(x) e(1/x) 1/x 2 2x/(x 2 + 1) cos(x)/sen(x) (3e(3x) + 2x)/(e(3x) + x 2) sen(log (arctg (x)))/((1 + x 2)arctg (x)) 5log (x)(5x) (log (x) 1) + (log (5x)(5x) log (x))/x (sen(x)arctg (x) (sen(x) 1))/(1 + x 2) + log (arctg (x))arctg (x) sen(x)cos(x)
Testes de composio de regras de derivao 57

Tabela 6.31

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 7

Execuo dos testes e anlise dos resultados


7.1 Execuo dos testes
Os testes apresentados no captulos anterior foram organizados em suites de testes e escritos no dialecto HtestML. Cada cheiro contem uma ou mais suites de testes, conforme indicado na tabela 7.1.

Suite
1 2 3 4 5 6 7 8 9 10 11

Testes
Converso de formatos: Valores numricos (Tabela 6.10) Converso de formatos: Formato externo e formato interno (Tabela 6.11) Converso de formatos: Validao sintctica (Tabela 6.12) Converso de formatos: Formato interno para formato externo (Tabela 6.13) Converso de formatos: Representao em rvore (Tabelas 6.14 e 6.15) Simplicao: Operaes algbricas bsicas (Tabela 6.16) Simplicao: Propriedades dos operadores algbricos (Tabelas 6.17 e 6.18) Simplicao: Funes (Tabelas 6.19 e 6.20) Simplicao: Validao semntica (Tabela 6.21) Simplicao: Qualidade (Tabelas 6.22, 6.23, 6.24, 6.25, 6.26, 6.27, 6.28 e 6.29) Derivao de expresses (Tabelas 6.30 e 6.31)

Ficheiro
ext2int_const.xml ext2int_transf.xml ext2int_vsint.xml ext2int_transf.xml reparv.xml simpl_op.xml simpl_op.xml simpl_func.xml simpl_vsem.xml simpl_qualid.xml derivar.xml

Tabela 7.1

Execuo de testes

O Testador invocado da linha de comandos de um interpretador Haskell, como no exemplo seguinte:

Testador> testador *** Teste de programas em Haskell *** Ficheiro XML com os testes a efectuar: derivar Executando testes em 'derivar.xml' ... Resultados em 'derivar_2005June6-001.txt'

58

Testes de Programas em Haskell

Teste e Qualidade de Software

Segue-se um extracto do cheiro de resultados da execuo Testador com o cheiro 'derivar.xml':

Resultados dos testes em 'derivar.xml' Execuo no 004 de 2005June6 Casos: Casos: Casos: Casos: Casos: Casos: 65 65 65 65 65 65 Tentados: Tentados: Tentados: Tentados: Tentados: Tentados: 0 1 2 3 4 5 Erros: Erros: Erros: Erros: Erros: Erros: 0 0 0 0 0 0 Falhas: Falhas: Falhas: Falhas: Falhas: Falhas: 0 0 0 0 0 0

### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='x^(x+1)'] esperado: "x^x(x+1)+log(x)x^(x+1)" obtido: "x^(x+1-1)(x+1)+log(x)x^(x+1)" Casos: Casos: Casos: Casos: Casos: Casos: Casos: 65 65 65 65 65 65 65 Tentados: Tentados: Tentados: Tentados: Tentados: Tentados: Tentados: 6 7 8 9 10 11 12 Erros: 0 Erros: 0 Erros: 0 Erros: 0 Erros: 0 Erros: 0 Erros: 0 Falhas: 1 Falhas: 1 Falhas: 1 Falhas: 1 Falhas: 1 Falhas: 1 Falhas: 1

### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='tg(3x^2)'] esperado: "6x(1+tg(3x^2)^2)" obtido: "6(1+tg(3x^2)^2)x" Casos: 65 Tentados: 13 Erros: 0 Falhas: 2 ### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='arcsen(x)'] esperado: "1/|(1+x^2)" obtido: "1/((1+x^2)^0.5)" Casos: 65 Tentados: 14 Erros: 0 Falhas: 3 ### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='arcsen(3x^2)'] esperado: "6x/|(1+9x^4)" obtido: "6x/((1+9x^4)^0.5)" Casos: 65 Tentados: 15 Erros: 0 Falhas: 4 ### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='arccos(x)'] esperado: "-1/|(1-x^2)" obtido: "-1/(-(1+x^2)^0.5)" Casos: 65 Tentados: 16 Erros: 0 Falhas: 5 ### Falha em: /TESTE[NOME='Derivacao de Expressoes']/TESTE[NOME='Derivadas simples']/ CASO_TESTE[FUNCAO='derivar' and AVALIAR='arccos(3x^2)'] esperado: "-6x/|(1-9x^4)" obtido: "-6x/((1+9x^4)^0.5)" Casos: 65 Tentados: 17 Erros: 0 Falhas: 6 Casos: 65 Tentados: 18 Erros: 0 Falhas: 6 Casos: 65 Tentados: 19 Erros: 0 Falhas: 6 ...

59

Testes de Programas em Haskell

Teste e Qualidade de Software

7.2 Anlise dos resultados


Cada execuo de uma suite de testes produziu um cheiro texto com os resultados. Antes de efectuar uma anlise mais aprofundada aos resultados dos testes apresenta-se, na tabela 7.2, os valores nais dos contadores para cada suite:

Suite
1 2+4 3 5 6+7 8 9 10 11

Testes
Converso de formatos: Valores numricos Converso de formatos: Formato externo e formato interno Converso de formatos: Validao sintctica Converso de formatos: Representao em rvore Simplicao: Operaes algbricas bsicas + Propriedades Simplicao: Funes Simplicao: Validao semntica Simplicao: Qualidade Derivao de expresses

Casos
20 12 14 18 33 19 4 42 65

Falhas
0 1 0 0 4 1 1 14 28 (0%) (8%) (0%) (0%) (12%) (5%) (25%) (33%) (43%)

Tabela 7.2

Resultados quantitativos da execuo de testes

Os testes das suites 1 a 9 so testes que tm como objectivo a deteco de falhas na especicao da aplicao. Os testes da suites 10 visam medir a qualidade da simplicao efectuada. Os testes da suite 11 tm como objectivo simultaneamente detectar falhas no processo de derivao e medir a qualidade da simplicao que efectuada derivada. No primeiro grupo (suites 1 a 9), verica-se que o processo de simplicao a nvel de operaes bsicas e suas propriedades o que tem o nvel de falhas mais elevado. falhas permitir averiguar sobre a sua gravidade. No segundo grupo (suites 10 e 11), verica-se que os nveis de falhas so igualmente elevados, o que revela que, de uma forma geral, a aplicao no simplica totalmente as expresses, relativamente ao que seria esperado. Nas seces seguintes efectuada uma anlise a estes resultados tendo em conta os objectivos denidos para cada teste. A anlise detalhada destas

7.2.1 Converso de formatos


Os grupos de testes referentes a converso de constantes do formato interno para o externo, validao sintctica e representao em rvore no apresentaram falhas, pelo que se conclui que, no conjunto dos casos apresentados, estes processos so correctamente efectuados. O grupo de testes que apresentou uma falha foi a converso de expresses do formato interno para o formato externo. A falha apresentada na tabela 7.3. Tal indica, no entanto, que a converso de expresses do formato externo para o interno no teve falhas no mbito dos casos de teste includos.

60

Testes de Programas em Haskell

Teste e Qualidade de Software

Avaliado
2|(x + 1 (x 5 cos(x)))

Esperado
|(x 1(x 5cos(x)))

Obtido
2|(x 1(x 5cos(x)))

Tabela 7.3

Falhas da converso de formato interno para formato externo

7.2.2 Simplicao
Operaes bsicas e as suas propriedades
O primeiro grupo de testes de simplicao incide na vericao das operaes bsicas e das suas propriedades. No mbito destes testes foram detectadas 4 falhas em 33 casos de teste, representando 15%. A tabela 7.4 apresenta os casos de teste com falhas:

Avaliado
5 + (5) 2+x+3 (2 + x) + 3 2 + (x + 3)

Esperado
0 x+5 x+5 x+5

Obtido
1 5+x 5+x 5+x

Tabela 7.4

Falhas da vericao de operaes bsicas e suas propriedades

Verica-se que destas falhas h uma muito grave sendo as outras trs menos graves. A primeira falha, na soma de um valor com o seu simtrico compromete seriamente todo o processo de simplicao, pelo deve corrigida de imediato. As trs falhas restantes devem-se ao facto de ser esperado um polinmio ordenado por grau e a aplicao no efectuar essa ordenao. Esta falha vai manifestar-se em muitos dos testes seguintes em que so esperados polinmios ordenados por grau. Como no afecta a correco do resultado, considerada de menor gravidade.

Avaliao de funes
Este grupo de testes acusou um falha num conjunto de 19 casos, apresentada da tabela 7.5:

Avaliado
cos(arcsen(1))

Esperado
0

Obtido
6.12303176911189e 017

Tabela 7.5
era obter o valor de

Falhas da converso de avaliao de funes

Esta falha resulta da aproximao de valores utilizada pelo interpretador do Haskell. A inteno

arcsen(1), no entanto, o valor obtido foi aproximado levando a que a funo cos no tivesse o valor de exacto, e consequentemente no assuma tambm exactamente
atravs da funo o valor zero. O valor obtido est em notao cientca podendo ser aproximado pelo valor zero. Da se conclui que, sob ponto de vista de avaliao de funes, a falha de pouca gravidade.

61

Testes de Programas em Haskell

Teste e Qualidade de Software

Validao Semntica
Este grupo de testes acusou uma falha na situao de diviso por zero. A falha no se vericou na validao em si mas na forma como o denominador foi simplicado, sendo o primeiro caso da tabela 7.4. Conclui-se que o processo de validao semntica no apresenta falhas da sua responsabilidade.

Qualidade da simplicao
Neste grupo de testes ocorreram 14 falhas nos 42 casos de teste, representando 33%, apresentadas na tabela 7.6:

Avaliado
4 + 3x + x 2 + 5x 2 + 4x + 6

Esperado/Obtido
6x 2 + 7x + 10 10 + 7x + 6x 2

(x 2 + 3x + 4) + 2(5x 2 + 4x + 6)

x 2 + 3x + 4 + 2(5x 2 + 4x + 6) x 2 + 3x + 4 + (2(5x 2 + 4x + 6))

4 + 3x + x 2

x 2 + 3x + 4 4 + 3x + x 2

(x + 1) (x + 1)

0 x + 1 + ((x + 1))

x 2 + 3x + 4 5x 2 4x 6 + 4x 2 + x + 2

0 0x 2 + 0x

x(x + 1)(x + 1)(x + 2)

(x + 1) 2x(x + 2) (x + 2)((x + 1) 2)x

(x + 1)x(x + 1)(x + 2)

(x + 1) 2x(x + 2) (x + 2)x((x + 1) 2)

(x + 1) 2(x + 2)(x + 1) 3

(x + 2)(x + 1) 5 (x + 2)((x + 1) 5)

sen(x)cos(x)sen(x)

sen(x) 2cos(x) cos(x)sen(x) 2

sen(x)x cos(x)sen(x) 2

sen(x) 3 x cos(x) cos(x)xsen(x) 3

x(x + 1)/x

x+1 (x + 1)x 0

(x + 1)(x + 2)/(x + 1)

x+2 (x + 2)((x + 1) 0)

((x + 1)(x + 2))/(x + 1)

x+2 ((x + 1) 0)(x + 2)

x (x + 1) + x (x + 1)

2x (x + 1) 2(x (x + 1))

Tabela 7.6

Falhas na qualidade da simplicao de expresses

62

Testes de Programas em Haskell

Teste e Qualidade de Software

Tal como em grupos anteriores, as falhas variam em nvel de gravidade. possvel identicar os problemas recorrentes que afectam a qualidade da simplicao:

Nos polinmios, os monmios no so ordenados por grau; Em produtos e divises, permanecem monmios com expoente zero que deviam ser simplicados para um e desaparecerem do produto;

Em somas, permanecem factores que multiplicam por zero que deviam ser eliminados; Em diferenas de expresses iguais, h casos em que a expresso resultante mais complicada do que a original;

Verica-se a presena de operadores de precedncia redundantes na expresso; Em produtos de funes, a ordem dos factores sempre invertida.

7.2.3 Derivao
Os testes de derivao englobam tambm testes de simplicao. Recorde-se que uma expresso antes de ser derivada simplicada. A expresso resultante da derivada tambm simplicada. Tendo-

se vericado que o processo de simplicao tem algumas falhas importantes, de esperar que os resultados dos testes de derivao apresentem muitas falhas. Por esse motivo, um sub-conjunto inicial desses testes analisa somente as regras de derivao sem simplicao. Os testes que se seguem a esse subconjunto incluem expresses que necessitam de simplicao e originam a derivadas que so tambm simplicadas. Neste grupo de testes ocorreram 28 falhas nos 65 casos de teste, representando 43%. Verica-se que na generalidade estas falhas so as mesmas analisada previamente no processo de simplicao, pelo que sero apenas apresentadas as que se devem exclusivamente ao processo de derivao ou que apresentam novas situaes anmalas no processo de simplicao. Estas falhas so apresentadas na tabela 7.6:

Avaliado
arcsen(x) arcsen(3x 2) arccos(x) arccos(3x 2) 1/(x + 3)

Esperado
1/|(1 + x 2) 6x/|(1 + 9x 4) 1/|(1 x 2) 6x/|(1 9x 4) 1/(x + 3) 2

Obtido
1/((1 + x 2) 0.5) 6x/((1 + 9x 4) 0.5) 1/((1 + x 2) 0.5) 6x/((1 + 9x 4) 0.5) 1/((x + 3) 2)

Tabela 7.7

Falhas no processo de derivao de expresses

Os dois primeiros casos apresentam falhas na simplicao. A raiz quadrada avaliada como uma potncia levando a discrepncia nos resultados. Embora o resultado da derivao esteja correcto, no est apresentando da forma mais conveniente, que seria com o operador de radiciao. Os dois casos seguintes representam a nica situao em que o clculo da derivada efectuado de forma errada. A regra de derivao da funo

arccos est implementada de forma diferente da especicao havendo no denominador uma troca do sinal + onde devia estar um sinal . Tal leva construo de uma expresso

63

Testes de Programas em Haskell

Teste e Qualidade de Software

que no corresponde derivada da funo. O ltimo caso apresenta tambm um erro no clculo. O denominador tem um sinal negativo que no era esperado no resultado. Todas as outras falhas (no includas na tabela 7.7), devem-se exclusivamente a detalhes de simplicao implementados de forma diferente da esperada. Por esse motivo, as derivadas calculadas esto correctas, mas simplicadas de forma diferente ou incompleta, de acordo com as falhas j identicadas no processo de simplicao.

64

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 8

Concluso
Este trabalho tinha vrios objectivos que foram lanando desaos medida que o desenvolvimento avanava. O primeiro deles foi a concepo de uma arquitectura de testes de programas em Haskell. Este objectivo foi atingido atravs da arquitectura de quatro componentes desenhada. A proposta

apresentada neste trabalho constitui um ponto de partida passvel de ser melhorado e implementado com mais funcionalidades. Para atingir este objectivo, foi necessrio efectuar o estudo de uma de testes unitrios. Sendo a linguagem Haskell o mbito do ambiente de testes, a

framework framework escolhida

ter que ser tambm implementada nesta linguagem. Aps alguma pesquisa na internet, foi encontrada a

framework

HUnit 1.0 que serviu de base arquitectura.

Um segundo objectivo do trabalho foi a denio de uma estratgia de concepo de casos de teste. A estratgia que melhor se adequa arquitectura desenvolvida a

data driven

que consiste em

executar sempre o mesmo cdigo de teste, fazendo variar apenas a funo a testar e o seu argumento. Para sistematizar e agilizar este processo, desenvolveu-se um dialecto XML, o qual de denominou de HtestML. Este dialecto, no tendo sido inicialmente denido como objectivo, revelou-se a representao mais adequada para a natureza hierrquica da organizao de casos de teste do HUnit 1.0. A concepo de casos de teste obrigou anlise de regras de especicao. Os casos de teste foram concebidos de forma a cobrir essas regras de forma vericar o seu cumprimento. Paralelamente, dada a natureza

dos processos de simplicao e derivao de expresses matemticas, conceberam-se casos de testes destinados a medir a qualidade das expresses produzidas por estes processos. Esta concepo implicou separar os vrios cenrios de criao de expresses em classes de equivalncia para que o nmero de testes fosse o mnimo necessrio para cobrir as regras de especicao. Como objectivo nal, pretendeu-se detectar falhas na aplicao em teste. Foram detectadas algumas falhas, no entanto, reconhece-se que tal tarefa no simples e exigiria um tempo de execuo mais alargado para obter resultados mais completos. A deteco de falhas na aplicao um exemplo

meramente ilustrativo das capacidades da arquitectura de testes. As perspectivas de trabalho futuro incluem o enriquecimento do dialecto HtestML, uma sada de

plain text e melhoramentos ao componente Testador de forma a incluir testes directos em funes com output para IO e tornar a sua execuo mais rpida.
resultados tambm para HtestML em vez de O desenvolvimento deste projecto revelou-se uma tarefa interessante tendo permitido tomar um primeiro contacto com uma ferramenta de teste de

software.

65

Testes de Programas em Haskell

Teste e Qualidade de Software

Captulo 9

Referncias
Bibliograa:

BURNSTEIN, Ilene -

Practical Software Testing, Springer, 2003 Concepts In Programming Languages, Cambridge University Press, 2003 Haskell, The Craft of Functional Programming, Addison-Wesley, 1996 Frmulas e Tabelas de Matemtica Aplicada,

MITCHELL, John C. -

THOMPSON, Simon -

ABELLANAS, Lorenzo, SPIEGEL, Murray R. McGraw-Hill, 1990

Stios na web :

http://www.haskell.org  Stio ocial da comunidade de programadores em Haskell

http://hunit.sourceforge.net  Stio da

framework

HUnit 1.0

66