• Nenhum resultado encontrado

O primeiro passo para possibilitar a utilização do ParFludan é garantir a exatidão dos seus resultados,

através de testes funcionais. Essa tarefa nem sempre é trivial, uma vez que em muitos dos casos que

se pretende estudar não existe termo de comparação disponível e a análise dos resultados tem de

ser feita exclusivamente com base no conhecimento e experiência dos engenheiros de barragens.

Ainda assim, foi definida uma estratégia de teste do programa baseada na ideia de considerar casos

simples, aumentando progressivamente a sua complexidade, admitindo que um conjunto de peças

simples garantidamente funcionais resulta numa peça mais complexa mas igualmente funcional.

No campo dos testes funcionais foram desenvolvidos e implementados dois tipos de testes: testes

unitários e testes de integração. Os testes unitários destinam-se a avaliar a funcionalidade de cada

diferentes cenários de simulação; de entre estes, são considerados tanto cenários teóricos, cujos

resultados expetáveis podem ser consultados na literatura, como cenários reais cujos resultados são

conhecidos por via numérica, quando disponível, ou experimental.

4.1.1 Testes unitários

Os testes unitários são usados para testar cada componente do programa durante o processo de

desenvolvimento, com o propósito de verificar o comportamento dessa componente específica, antes

de ser reunida com as restantes componentes para formar o programa completo. Estes testes devem

ser tão simples quanto possível e independentes entre si e de outras componentes do programa, de

forma a que seja possível executar os testes de uma componente em particular sem quaisquer

dependências de outras componentes.

A garantia de que os testes unitários definidos para uma certa componente estão corretos é da

responsabilidade do programador dessa componente, que conhece o seu funcionamento expetável. É

boa prática de programação definir pelo menos um pequeno conjunto de testes unitários para cada

peça do programa que se está a construir. Uma vez disponível, o conjunto de testes unitários deve

ser executado sempre que é feita uma alteração no código ou uma compilação para execução; desta

forma, é garantido que as alterações introduzidas não produziram efeitos imprevistos.

Como exemplo, consideremos a função que soma dois números a e b, divide por um terceiro c e

retorna o resultado, f(a,b,c)=a+bc. Como testes unitários para esta função poderiam ser definidas as

seguintes asserções:

• f(1,2,3)==1

• f(-1,2,5)==0.2

• f(10,-10,8218)==0

• f(1,2,0)==ERRO (indeterminação)

Ao serem executados o testes unitários, estas igualdades seriam testadas e caso não fossem

verificadas o programa altertaria o utilizador para o facto de alguns dos testes unitários estarem a

falhar.

No contexto do ParFludan, os testes unitários estão definidos dentro da pasta src/. No caso dos

módulos do programa principal, para cada módulo existe um ficheiro .c com o mesmo nome

acrescentado do prefixo “test_”, onde estão definidos os seus testes unitários. O scriptrunCtests.sh

reúne e executa todos estes testes, falhando com uma mensagem de erro caso algum dos testes não

passe; este script é executado sempre que o script runtests.py é chamado (ver secção 5.5) e pode

também ser executado isoladamente.

No caso dos módulos auxiliares, os testes estão definidos dentro da pasta src/tests. Estes testes são

também executados quando o script runtests.py é chamado, e para executar todos os testes aos

módulos auxiliares (e, mais geralmente, todos os testes a módulos python), basta executar na pasta

$ python –m unittest discover

12

É possível e desejável que o próprio utilizador acrescente testes unitários, em especial no caso de

desenvolver uma nova funcionalidade para o programa; os detalhes sobre como o fazer estão

disponíveis na secção 6.1.

4.1.2 Testes de integração

Mesmo que todas as componentes do programa tenham testes unitários bem definidos e que todos

eles passem sem erros, não é garantido que o conjunto das várias componentes, uma vez reunidas,

funcione da maneira esperada. Para fazer essa verificação é necessário definir testes de integração,

onde o programa completo é submetido a um cenário de execução e os resultados obtidos são

comparados com os esperados. Os testes de integração são na verdade o principal teste à

funcionalidade do programa e uma etapa indispensável no processo de verificar a integridade dos

resultados obtidos.

Para definir um teste de integração são necessárias duas partes: por um lado, é preciso definir um

cenário de execução correspondente aos dados de entrada para o programa; por outro, é necessário

dar alguma medida dos resultados esperados de forma a que se possa verificar a exatidão dos

resultados obtidos. No âmbito do ParFludan são distinguidos dois tipos de testes de integração,

considerando casos teóricos e casos reais. Os casos teóricos correspondem a cenários ideais,

descritos tipicamente na literatura de engenharia de estruturas, onde tanto os dados de entrada (a

malha, as ações, etc) como os resultados (deslocamentos, tensões, etc) estão definidos a nível

teórico. Os casos reais correspondem a cenários não-ideais, tipicamente provenientes de estruturas

estudadas no âmbito de outros trabalhos, onde os dados de entrada estão bem definidos mas os

resultados, em vez de terem origem teórica, provêm de dados experimentais ou de simulações do

mesmo cenário feitas previamente com algum outro programa, e dos quais existe consequentemente

um conhecimento menos exato do que nos casos com soluções analíticas.

Os cenários para testes de integração são definidos na pasta tests/testdata, que replica a estrutura da

pasta data/, isto é, para cada cenário é necessário criar uma pasta em tests/testdata com o nome do

cenário e incluir todos os ficheiros necessários para o executar, tal como se fosse um cenário normal

para execução. A nível do programa não é feita qualquer distinção entre casos teóricos e casos reais.

Quando é definido um cenário para teste de integração, devem também ser definidos na pasta

tests/teststandards/ os resultados esperados caso a simulação decorra como previsto. Para cada

cenário existe uma subpasta dentro desta com o nome do cenário e dentro da qual estão os

resultados “corretos”, ou pelo menos esperados, na mesma forma em que vão ser produzidos pela

simulação, para que depois possam ser comparados.

Para executar os testes de integração existem duas hipóteses: usando o script run.py ou o script

runtests.py. Por um lado, a forma mais simples é usar o scriptrun.py para executar um dos cenários

exatamente da mesma forma que se faria se fosse um cenário real e não um teste – a única

particularidade a ter em conta é que deve ser escolhida a pasta tests/testdata como fonte de dados,

em vez da pasta data/ definida por omissão (ver secção 5.4).

Por outro lado, para executar um cenário e comparar os resultados obtidos com os resultados de

referência deve ser usado o scriptruntests.py, que inclui três operações:

1. Execução da simulação com o ParFludan;

2. Execução da simulação com o Fludan-RAS (sequencial);

3. Comparação dos resultados das várias simulações entre si e com os de referência.

O primeiro passo é equivalente a executar o run.py, com a vantagem de que pode ser chamado

múltiplas vezes para diferente número de processadores – o que é importante para garantir que os

resultados são consistentes entre si independentemente do número de processadores usado. O

segundo passo corresponde a executar a simulação com uma versão do programa sequencial

original (disponível em src_seq/), em vez do ParFludan; a definição de que versão deve ser

executada para cada cenário, se alguma

13

, é feita dentro do script runtests.py, sendo usada por

omissão a versão disponível em src_seq/fludan/. Por último, o runtests.py indexa os resultados

criados nos passos 1 e 2 e compara-os entre si e com os resultados de referência definidos (caso

existam), lançando avisos e eventualmente abortando a execução caso as diferenças encontradas

excedam a tolerância definida

14

.

Além dos cenários de teste disponíveis, o utilizador pode adicionar novos cenários para verificar

novas funcionalidades ou simplesmente diversificar o conjunto de testes (ver secção 6.1). Por

omissão o runtests.py executa todos os testes de integração disponíveis, mas é possível restringir a

execução apenas a um subconjunto dos cenários existentes. A secção 5.5 descreve os detalhes de

como utilizar esta e outras funcionalidades do scriptruntests.py.

Documentos relacionados