Testes Unitários na prática com Spring, TestNG, Mockito e Maven 2 : Parte 1

Neste post vou mostrar como podemos criar testes unitários para aplicações desenvolvidas com Spring usando o TestNG. Além disto usarei o framework para mocks chamado Mockito com isto será possível simular o comportamento de certos objetos para realizar o testes. No final vamos rodar estes testes com o Maven.

Se quiser saber mais sobre testes, Q.A e Maven sugiro que leia meus postas anteriores:
Testes unitários com o TestNG

O testNG é um framework para testes unitários feito em Java para Java :). A solução é bem mais flexível do que o JUnit que é a solução mais tradicional de testes unitários em Java. O testNG prove mais facilidades do que o JUnit principalmente quando realizamos testes em grupos, esta funcionalidade eh útil para testar grupos de funcionalidades ou requisitos específicos.



Para uma comparação detalhada que vai de encontro a superioridade do testNG confira este link. Vou utilizar os recursos de integração do testNG com Spring. Vamos ver como injetar beans para testes e como utilizar o Mockito nos testes.

Mocks com o Mockito

Mockito é um excelente solução para mock objects. Por que além de muito simples, você trabalha com uma DSL muito focada e expressiva. O Mockito facilita muito a nossa vida por que podemos criar os mocks direto nos testes unitários evitado a necessidade de criar outras classes.

Claro que se necessário podemos criar classes para aproveitar os objetos mocks, podemos fazer isto usando o Spring e injetar uma classe cheia de mocks.

Estruturando os testes

Existem várias formas de estruturarmos os nossos testes unitários. Eu acredito que o melhor uso é quando temos um método para cada necessidade, como podemos realizar esta quebra? Das seguintes formas:
  • Um método por cenário, para que usa casos de uso.
  • Um método por feature, para quem usa FDD por exemplo.
  • Vários métodos por requisitos, no caso de uma metodologia tradicional como o RUP.
  • Os método são criados conforme o caso de teste do Analista de Testes, um por cenário.
E assim por diante... Existem diversas outras estratégias que poderíamos estar adotando. O TestNG nos permite aplicar diversas marcações em um teste, por exemplo, podemos dizer que um método de testes serve para o requisito funcional RF005 e a o caso de uso 10 cenário alternativo 3 por exemplo. Então com os grupos de testes podemos rodar os testes por requisitos ou por casos de uso por exemplo.

Tudo isso ajuda na hora de aplicar testes em cima de um conjunto de funcionalidades ou requisitos por exemplo na hora de fazer o deploy. Uma boa prática é rodar todos os testes sempre, a aplicação como um todo deve estar sempre funcionando, mas podemos criar uma certa rastreabilidade dos testes com os requisitos ou casos de uso.

Dependendo do projeto uma matriz de impacto ou rastreabilidade é suficiente, mas ter este mapeamento nos testes ajuda a acelerar as coisas.

Usando TestNG com Mockito

Quando criamos um teste unitário com o testNG é possível usar o Mockito para os objetos do teste e bem como para as dependências de sua aplicação. Desta maneira você consegue ter um isolamento total do seu código do resto da aplicação. Ainda é possível ter o seu código mesmo com dependências de outros pontos da aplicação que não estão prontos ainda.

Tudo junto na Prática

Vamos a uma aplicação de exemplo que fiz com todas estas soluções. A aplicação é fictícia serve para mostrar a integração desta solução como um todo e como usar o testNG com Spring e Mockito. Então sem mais delongas vamos a aplicação.

Vamos supor que estamos desenvolvendo uma solução de gestão de vendas de produtos para algum segmento do mercado. Então no nosso domínio fictício existem as seguintes entidade:
  • Produto
  • Item
  • Vendedor
  • Venda
  • Comissao
O Produto representa um produto qualquer como um sapato ou meia. O Item possui um Produto e um valor e bem como quantidade e preco. Você poderia utilizar outro tipo de modelagem mas este modelo lhe permite lidar com produtos promocionais e descontos em vendas de quantidades elevadas.

O Vendedor é o responsável pela Venda. Neste modelo poderíamos adicionar o Cliente, dados e entrega, forma de pagamento e muito mais, deixei o modelo restrito para facilitar o entendimento dos testes.

Por fim existe a Venda que contem uma lista de items e bem como um Vendedor. Você pode conferir isto no seguinte diagrama de classes a baixo:

Diagrama de classes do modelo

Certo agora vamos aos serviços da aplicação. Esta aplicação poderia ter vários serviços, por motivos de simplificação e foco do post vou usar apénas 2 serviços sendo que um deles não foi implementado ainda, então vamos aos serviços e as suas implementações:
  • ItemService
  • VendaService -> VendaServiceImpl
São estes dois serviços a cima. Sendo que o serviço ItemService ainda não tem implementação e o Serviço de Vendas tem a implementação padrão chamada VendaServiceImpl. A implementação do serviço de vendas depende do serviço de items, mas esta dependência é feita através das interfaces(contratos). Confirma o seguinte diagrama de classes:

Diagrama de classes dos Serviços

Podemos trabalhar com dois cenários. Imagine que você desenvolveu o serviço de vendas ou tem que desenvolver o mesmo e o serviço de items não esta pronto ainda. É possível tocar este desenvolvimento em paralelo, isto é feito através do contrato dos serviços(interfaces) e ainda é possível testar seu código mesmo sem o serviço de item estar pronto para isso vamos usar o TestNG com o Mockito.

Em um segundo cenário o serviço de items está pronto, mas a sua implementação foi feita por outra pessoa e é muito duvidosa, logo você pode ter certeza que o seu código esta ok ou se o problema é no serviço de items, logo você também poderia usar o Mockito com o TestNG para isolar a aplicação e testar somente esta parte.

No próximo post vou mostrar os códigos desta aplicação além de discutir mais sobre teste unitários, Spring e Mockito. Você pode baixar os diagramas que fiz no EA neste url.

Abraços e até a próxima.

Popular posts from this blog

Kafka Streams with Java 15

Rust and Java Interoperability

HMAC in Java