Introdução

Tem-se visto muitas pessoas dizendo por aí que o único teste que pode ser feito com Junit são os famosos teste unitários, ou seja, testar uma única funcionalidade do seu sistema. Esse artigo procura mostrar como testes de integração também podem ser feitos na sua aplicação. Serão utilizados exemplos práticos que estão executando em sistemas reais em produção por muitos anos. Primeiramente teremos uma breve introdução sobre que é Junit, e o que são testes de integração, por fim será mostrado como um teste de integração é realizado.

Junit

Junit é um framework de código aberto inicialmente desenvolvido por Kent Beck e Erick Gamma. O Junit permite a criação de testes automatizados utilizando Java. É importante salientar que ele permite a criação de testes automatizados, num sentido geral e não que ele somente seja utilizado para testes unitários.

O framework JUnit facilita muito a criação de código para os testes além de apresentar os resultados do teste de forma bastante clara e visível. Se todos os testes forem executados com sucesso, é apresentada uma barra verde ao desenvolvedor, caso contrário tem-se uma barra vermelha com uma indicação de onde ocorreu a falha do teste.

Para começar a utilizar JUnit basta criar uma classe que estenda junit.framework.TestCase e definir cada método a ser testado sendo que ele seja público, sem retorno de argumentos e que seu nome tenha o prefixo test, como por exemplo testXxx(). Também pode ser utilizada a notação @test em cima do método tornando-o assim um método testável. Por exemplo:

Listagem 1: Exemplo de método testável

import junit.framework.*;
class SuaClasseDeTeste extends TestCase
{
	public int testSeuTeste() {
		...
	}
}

Para saber mais sobre Junit acesse o artigo “Testes de unidade com Junit”.

Nosso objetivo aqui é mostrar um teste de integração na prática com essa ferramenta, portanto se você ainda não está familiarizado com Junit dê uma olhada no artigo sugerido.

Além das vantagens citadas, o JUnit ainda tem um excelente suporte que é dado pela forte comunidade de desenvolvedores que utilizam o utilizam. Junit é elegante e muito simples, tornando o teste bastante simples de ser feito, além de que uma vez escritos, todos os testes são executados rapidamente sem atrapalhar o processo de desenvolvimento. JUnit checa os resultados dos testes e fornece respostas imediatas ao programador.

A instalação do Junit é muito simples, basta adicionar o arquivo junit.jar no classpath para compilar e rodar os programas de teste. Porém, se você estiver utilizando o framework Eclipse, Jbuilder ou Netbeans ele já vem configurado.

Teste de Integração

Segundo o autor Somerville há basicamente três fases de testes: de unidade, de integração e de sistema.

Os testes de unidade são testes de componentes individuais. Os testes do sistema resultam dos testes da união dos componentes de hardware e de software. Os testes de integração são os testes das interações entre componentes de software, ou seja, é o caminho no qual o teste é conduzido para integrar componentes no sistema. O teste de integração é o processo de verificar se os componentes do sistema, juntos, trabalham conforme descrito nas especificações do sistema e do projeto do programa.

Na fase de teste de integração, o objetivo é encontrar falhas provenientes da integração interna dos componentes de um sistema. Geralmente os tipos de falhas encontradas são de transmissão de dados. Por exemplo, um componente A pode estar aguardando o retorno de um valor X ao executar um método do componente B; porém, B pode retornar um valor Y, gerando uma falha. Não faz parte do escopo dessa fase de teste o tratamento de interfaces com outros sistemas (integração entre sistemas). Essas interfaces são testadas na fase de teste de sistema e não teste de integração.

Teste de Integração na Prática

Muitos perguntam como fazer teste de integração com Junit testando desde as camadas iniciais até o Banco de dados e nisso tudo juntando vários componentes.

Algumas situações devem ser pensadas como: O que testar? Como testar? Como manter o banco de dados sem sujeiras?

O que deve ser testado deve ser verificado pelo desenvolvedor o qual precisa entender qual funcionalidade do sistema precisa de uma verificação. Por exemplo, o desenvolvedor pode querer testar como é feita uma operação de débito numa conta corrente, nessa situação ele deve verificar que o programa debitou ucerta quantia de dinheiro no banco de dados e o resultado retornado do saldo trouxe a quantia anterior ao débito subtraído da quantidade que foi inicialmente passada.

A pergunta de Como testar deve ser respondida utilizando Junit, sua IDE como Eclipse e a linguagem de programação Java.

Por fim, deve ser feita uma estratégia que não deixe sujeiras no Banco de dados após as operações terem sido concluídas.

Exemplo de um Teste de Integração

Aqui será mostrado como é feito um teste de integração completo num sistema de administração de medicamentos. O que vamos testar aqui basicamente é a inserção de um paciente e sua exclusão. O importante nesta exemplificação não é se ater aos detalhes do que está dentro da classe PacienteRN ou o que está na classe DadosPaciente mas sim como é feita a sequência dos testes e porque ela foi realizada desta forma.

Abaixo é mostrada a seqüência das operações para este estudo de caso.

Listagem 2: Teste de inclusão de um Paciente no sistema

//Inclui Paciente
Log.log("Incluindo um paciente no Sistema..."); 
PacienteRN paciente = new PacienteRNImpl();
paciente.inclui( DadosPaciente.getED() );

Log.log("Paciente incluído com sucesso: " + DadosPaciente.getED().getNomePac()); 

Inicialmente no teste acima inserimos um paciente no sistema. Repare que todo o processo de inserção do paciente é feito aqui, ou seja, o sistema primeiramente recebe os dados do paciente através do método “inclui” que já recebe uma classe com gets e sets com os dados do paciente já previamente configurados e armazena no banco de dados o paciente que é feita pela camada de acesso a dados depois que o método inclui() chamá-la. Estamos começando os testes passando dados pela camada de negócio, no entanto, isso poderia ser feito ainda uma camada anterior, como na camada de Bean de Interface, passando dados para essa camada que chamaria a camada de negócio que, por sua vez, chamaria a camada de Banco de dados.

Listagem 3: Teste de consulta de um Paciente no sistema

//Consulta Paciente
Log.log("Consultando um paciente no Sistema...");
PacienteED pacienteED = paciente.consulta(DadosPaciente.getED());

Assert.assertEquals( pacienteED.getNomePac(), .getED().getNomePac());
    
Log.log("Paciente consultado com sucesso: " + DadosPaciente.getED().getNomePac());

No código acima testa-se se o paciente realmente foi inserido no Banco de Dados. Uma asserção é realizada para verificar se a inclusão do paciente foi realizada com sucesso. Alguém poderia perguntar o porquê do código da listagem 2 ter dito que o paciente foi incluído com sucesso se apenas no código da listagem 3 foi verificado efetivamente no Banco de Dados a inclusão do paciente. Isso ocorre porque no código da listagem 2 é feita uma inclusão e espera-se que nenhum erro mais complexo tenha ocorrido, como um null pointer ou alguma quebra de integridade ou qualquer falha que impeça a inclusão. Porém, se a consulta da listagem de código 3 não resultar nos dados esperados, ocorre um erro em que não foi encontrado este paciente no Banco de Dados, portanto não foi incluído corretamente por algum motivo não aparente na qual devido alguma situação não retornou uma falha.

Listagem 4: Teste de exclusão de um Paciente no sistema

//Exclui o Paciente
Log.log("Excluindo o paciente do Sistema..."); 
    
paciente.exclui( DadosPaciente.getED() );

Log.logLast("Paciente excluído com sucesso: " + DadosPaciente.getED().getNomePac());

Listagem 5: Teste de consulta de um Paciente no sistema

//Consulta Paciente
Log.log("Consultando um paciente no Sistema...");
pacienteED = paciente.consulta(DadosPaciente.getED() );

Assert.assertNull(pacienteED);

Novamente no código acima verificamos se o paciente não se encontra mais no Banco de dados.

Vale salientar que caso um determinado dado não devesse sofrer uma exclusão no sistema, mesmo assim este dado deveria ser excluído no final de todo o processo para manter a limpeza no Banco de Dados. Caso contrário, a cada execução do teste estaríamos adicionando cada vez mais dados no Banco de Dados, acumulando muita sujeira e podendo inclusive quebrar o teste se não for possível inserir os mesmo dado no Banco de dados.

Algumas pessoas me perguntaram por que não utilizar Jmock neste caso. Pessoal, novamente vou salientar que isso é teste de integração, queremos ver toda operação sendo realizada, desde as primeiras camadas até a gravação final no Banco de dados. Jmock é excelente para testes de unidade, mas aqui no nosso caso não se aplicam.

Conclusão

Este artigo buscou mostrar de forma bem simples como é realizado um teste de integração simples, onde diferentes componentes são testados em conjunto. Muitas pessoas buscam por um exemplo simples e compreensível mostrando como é feito um teste de integração em conjunto com a camada de acesso a dados, espero que esse artigo tenha esclarecido um pouco melhor como isso é feito. Espero que tenham gostado e qualquer coisa vocês já sabem meu e-mail, respondo a todos e-mails, podem enviar.

Bibliografia

  • Engenharia de Software - 9ª Edição 2011 - Ian Sommerville
  • Análise de Software Processos, Princípios e Técnicas - Mauro Pezzè
  • Junit - http://www.junit.org/