Atenção: esse artigo tem um vídeo complementar. Clique e assista!
Será apresentado a ferramenta Pex e discutido o uso dela dentro de técnicas de desenvolvimento orientado a testes baseadas em Test Driven Development.
Em que situação o tema é útil
O Microsoft Pex é uma ferramenta de testes de caixa branca que gera automaticamente o código de testes unitários, visando efetuar uma máxima cobertura de código. Testes de unidade é um importante recurso para garantir a qualidade do código que produzimos. Qualquer projeto que possa sofrer alterações algum dia (ou seja, todos!) pode se beneficiar do uso de testes para validar se as modificações efetuadas não introduziram novos bugs. Além disso, dentro do TDD, os testes são importantes para a documentação e o próprio design dos sistemas.
Geração automática de testes numa abordagem TDD
O Pex é uma ferramenta de exploração de código para testes unitários. A princípio, o uso desse tipo de aplicação permite a geração de código de validação das funcionalidades já existentes de um sistema, mas será que este é o seu único uso? Neste artigo, veremos os conceitos do Pex e como ele pode ir além da criação automática de testes para código legado numa abordagem TDD.
Nos últimos anos, as disciplinas de testes vêm tomando a importância que lhes é de direito. Na prática, está deixando de ser algo passivo, onde simplesmente recebiam dos desenvolvedores os artefatos a serem testados, para se tornarem uma doutrina ativa e obrigatória, guiando o desenho e arquitetura das aplicações antes mesmo de qualquer linha de código ser produzida. O aumento da aceitação e aplicação de TDD (Test-Driven Development) não deixa dúvidas sobre o fato, além da crescente valorização dos profissionais especializados nessa área.
Ferramentas têm sido criadas para apoiar o uso de testes. Frameworks de criação e execução de testes de unidade; bibliotecas para a criação de objetos dublês (stubs e mocks); aplicativos que automatizam testes de interface gráfica e usabilidade; simuladores de chamadas em massa para averiguação de desempenho e estabilidade; entre outros tipos. E dentre esta gama de opções temos o Pex. O Pex é uma ferramenta desenvolvida pela Microsoft Research para a exploração de código e geração automática de testes unitários seguindo uma abordagem de testes de caixa branca.
Neste artigo daremos foco em como trabalhar com o Pex, desde sua utilização mais básica e comum até seu uso com técnicas de TDD. Nos exemplos que iremos demonstrar, faremos uso da ferramenta de testes do Visual Studio (MSTest). No entanto, o Pex foi desenhado para suportar outros frameworks como o MbUnit ou o nUnit.
Testes de unidade como testes de caixa branca
Testes de caixa branca, também conhecidos como testes estruturais, é um tipo de teste onde são avaliados todos os caminhos lógicos que podem ser tomados dentro do código durante o fluxo de execução. O seu objeto é permitir uma alta cobertura de código, exercitando cada trecho para garantir que ele seja executado pelo menos uma vez, não permitindo que um comportamento que não foi validado entre em produção e que consequentemente possa conter alguma anomalia. Por isso, é essencial que os detalhes de sua implementação interna sejam conhecidos para análise, pois precisamos saber quais parâmetros de entrada devem ser fornecidos para que todos os fluxos de execução sejam percorridos. Isso o difere dos testes de caixa preta, categoria de testes onde não temos ideia de como o sistema foi desenvolvido e por isso testamos apenas a funcionalidade, geralmente apenas através da interface gráfica.
Testes de unidade são categorizados como testes de caixa branca. Os testes de unidade são escritos na forma de exemplos, ou seja, dada uma entrada temos uma determinada saída (um valor ou um comportamento) após a execução da funcionalidade que está sendo verificada (geralmente um método). Fazemos isso de forma que todas as opções de entradas e saídas sejam testadas, obtendo uma alta cobertura do sistema.
Existe um padrão para a escrita de testes unitários. Em primeiro lugar, os parâmetros do teste são preparados, por exemplo, criando objetos e ajustando os valores. Em seguida, vem a execução da funcionalidade que está sendo testada, também conhecida como SUT (System Under Test). Na prática, é a própria chamada ao método que está sendo validado. Por último, temos a confirmação dos valores resultantes dessa execução, ou seja, se o valor que esperávamos é mesmo o que foi obtido no teste. Opcionalmente temos uma quarta etapa que é a limpeza, por exemplo, a remoção de objetos em memória, mas que na prática é raramente necessário para testes de unidade. Este padrão é conhecido como Arrange-Act-Assert, uma referência às fases de preparação, execução e verificação citadas anteriormente.
Vemos na Figura 1 um diagrama exemplificando testes de unidade onde são testados todos os caminhos possíveis do método VerificarNegativo(int). Este método valida se um número inteiro tem valor negativo, retornando true caso isso seja verdade ou false no caso contrário. Podemos ver que para a cobertura total desse método, precisamos de apenas dois casos de testes (exemplos), passando como parâmetros um número negativo e outro positivo (fase “arrange”), executando o método (fase “act”) e confirmando que os resultados são true e false, respectivamente (fase “assert”). Poderíamos também passar outros valores, como zero, -999 ou um milhão, mas na prática esses exemplos de testes adicionais não trariam maior relevância, pois apenas repetiríamos a execução dos fluxos já validados.
Figura 1. Exemplo de Arrange-Act-Assert
Os testes de unidade não são importantes apenas para validar todos os fluxos de execução possíveis, mas também (e principalmente) para servirem de confirmação quando houver alguma alteração de código no sistema. Feita a modificação, os testes de unidade existentes podem ser executados e caso algum deles retorne falha (ou “quebre”, como é geralmente dito) podemos saber qual funcionalidade foi impactada e a partir disso efetuar a correção.
Pex e testes de unidade parametrizáveis (PUT)
O Pex é uma ferramenta que gera automaticamente os testes de unidade, buscando cobrir todos os caminhos de execução possíveis. Ou seja, dado um método que queremos testar, o Pex poupa o seu trabalho, analisando quais são os parâmetros de entrada relevantes e montando todos os testes necessários.
...