Este documento apresenta um curso sobre testes automatizados, abordando testes unitários, de integração e funcionais. A unidade III discute testes de integração com ênfase em TestNG, Mockito, testes com banco de dados usando DBUnit e Seam.
2. Conteúdo Pragmático
● Unidade I
● Introdução a teste de software
● Introdução a automação de teste de software
● Básico sobre teste unitário
● Unidade II
● Técnicas de Teste Unitários
● TestNG
● Mockito
● Unidade III
● TestNG e Mockito
● Testando com Banco de Dados
● DBUnit e Seam
● Unidade IV
● Testes Funcionais
● Selenium
● Princípios e Filosofia de Testes Automatizados
3. Agenda
● TestNG
● Mockito
● Pratica
● Teste com banco de dados
● DBUnit e o Seam 2
● Pratica
4. Requisitos
● JBoss Developer Studio 4.x
● Jboss AS 5
5. TestNG - Anotações
Anotação Objetivo
@Test Marca um método como teste
Marca um método para ser executado
no carregamento da classe de teste.
@BeforeClass (executado antes de todos os outros
métodos e apenas uma vez)
Marca um método para ser executado
no após a execução de todos os
@AfterClass métodos da classe de teste. (apenas
uma vez)
Marca um método para ser executado
@BeforeMethod antes de cada método de teste
Marca um método para ser executado
@AfterMethod após cada método de teste
7. TestNG - Asserts
Asserção Objetivo
assertEquals(objeto1,objeto2 Afirma se os objetos possui os
mesmos valores.
)
assertFalse(boolean Afirma se condição é falsa
condição)
assertNull(objeto) Afirma se objeto é null
assertSame(objeto1,objeto2) Afirma se objeto1 e objeto2 apontam
para mesma referência
assertTrue(boolean Afirma se condição é verdadeira
condição)
fail() Lança uma falha no teste
10. Mockito - Exemplos
● Mockito.when(usuarioRepository.buscar(1L)).tthe
nReturn(null);
● Quando o mock “usuarioRepository” chamar o
método “buscar” recebendo como parâmetro o long
“1L” deve retornar null.
● Mockito.verify(usuarioRepository).atualizar(usuár
io);
● Verifique se o mock “usuarioRepository” teve o seu
método “atualizar” chamado uma vez recebendo um
usuário como parâmetro (Obs.: A verificação do
objeto usuário sera através do seu “equals”)
11. Mockito - Exemplos
● Mockito.verify(usuarioRepository,Mockito.times(2)
).atualizar(usuário);
● Verifique se o mock “usuarioRepository” teve o seu
método “atualizar” chamado 2 vezes recebendo um
usuário como parâmetro
● Mockito.doThrow(new
PontoException()).when(usuarioRepository.busca
rUsuarioPorEmail(email));
● Quando chamar o método “buscarUsuarioPorEmail”
do mock “usuarioRepository” lance a exceção
“PontoException”.
13. PowerMock
● PowerMock usa um classloader personalizado
e manipula bytecodes para habilitar mocks de
métodos estáticos, construtores, classes e
métodos finais, métodos privados e muito
mais.
14. Mockito e PowerMock
● O PowerMock estende funcionalidade do
Mockito e prove uma lib de integração entre os
dois frameworks.
● Exemplo de mock para static class.
1. Adicionar @PrepareForTest na classe de teste
– @PrepareForTest(DataUtil.class)
2. Chamar PowerMockito.mockStatic() para
habilitar o static mock
– PowerMockito.mockStatic(DataUtil.class);
15. Mockito e PowerMock
● Exemplo mock static class
3. Use o Mockito.when() para determinar o comportamento
esperado
– Mockito.when(DataUtil.getDataHoraAtual()).thenReturn(
getDataHoraAtual(12, 0));
4. Para que o PowerMock funcione corretamente como o
TestNG você precisa configurar o TestNG para usar a fabrica
de objetos do PowerMock
– @ObjectFactory
public IObjectFactory getObjectFactory() {
return new
org.powermock.modules.testng.PowerMockObjectFactory();
}
17. Projeto Ponto
● Atualmente é muito comum as pessoas
trabalharem de casa (home office). E as vezes
os horários de trabalho são bem flexíveis O
nosso objetivo será criar um site onde as
pessoas possam ter seu ponto pessoal
controlando suas horas de trabalho de forma
simples e rápida
18. 1° Versão de ter as seguintes ações
● Registar Usuários
● Registrar hora de inicio do ponto
● Registrar hora fim do ponto
● Listar histórico de pontos por usuário
19. Especificação
● Registro de usuário
● Sistema deve permitir salvar, atualizar, obter e remover
usuários
● Nome e e-mail são obrigatórios
● Registrar ponto inicial
● Não é possível registrar novo ponto se houver ponto em
aberto
● O ponto pode ser registrado para um usuário através do e-
mail ou id
● Registrar ponto final
● Buscar o ponto que estiver em aberto e fechar.
22. Exercício
● As interfaces das classe de negocio já estão
cerca de 90% feitas mas, estão sem teste
unitários e de integração
● Objetivo é implementar todos os testes
unitários implementação que esteja faltando.
23. Teste com banco de dados
● Aplicações com banco de dados apresentam
um grande desafio para automação de teste.
● Os testes que interagem com banco de dados
tendem a ser bem mais lentos que os testes
que rodam inteiramente na memoria.
● “Quando há alguma maneira de testar sem um
banco de dados então teste sem o banco de
dados!”,
24. Por que testar com banco de
dados?
● Banco de dados é parte necessária em muitas
aplicações, então verificar a sua corretude é
parte necessária na construção da aplicação
● Já que temos que testar, interações com banco
de dados, uma pratica fundamental em quase
todos os projetos é o uso do padrão Database
Sandbox que permite isolar o BD de
desenvolvedores, testadores da base de
produção (e uns aos outros).
25. ● Um Database Sandbox para cada desenvolvedor. Compartilhamento de
um banco de dados entre os desenvolvedores é uma falsa economia.
● Você faria um encanador e um eletricista trabalharem na mesma parede,
ao mesmo tempo?
26. DBUnit
● DbUnit é uma extensão do JUnit destinado a
banco de dados e orientado projetos que, entre
outras coisas, coloca o seu banco de dados em
um estado conhecido entre as execuções de
teste.
● É uma excelente maneira de evitar problemas
que podem ocorrer quando um caso de teste
corrompe o banco de dados e faz com que os
testes subsequentes falhem.
27. Principais componentes
● IDatabaseConnection
● Intefarce que representa conexão DBUnit com o
banco de dados
● IDataSet
● Interface que representa uma coleção de tabelas
● DatabaseOperation
● Classe abstrata que representa uma ação realizada
no banco de dados antes e após cada teste
28. Principais componentes
● IDatabaseConnection team seguintes classes concretas
● DatabaseConnection
● DatabaseDataSourceConnection
● IDataSet
● FlatXmlDataSet - Lê e escreve documento XML dataset. Cada
elemento XML corresponde a uma linha da tabela.
– <dataset>
<TEST_TABLE COL0="row 0 col 0"
COL1="row 0 col 1"
COL2="row 0 col 2"/>
</dataset>
29. Principais componentes
● DatabaseOperation
● As duas operações mais úteis são REFRESH e CLEAN_INSERT. Eles
são os que você vai lidar normalmente. Elas representam duas
estratégias com diferentes benefícios e compensações.
● DatabaseOperation.UPDATE
– Esta operação atualiza o banco de dados a partir do conteúdo dataset. Esta
operação pressupõe que os dados da tabela já existem no banco de dados alvo
e vai falhar se este não for o caso
● DatabaseOperation.INSERT
– Esta operação insere o conteúdo do dataset no banco de dados. Esta operação
pressupõe que os dados da tabela não existe no banco de dados alvo e e vai
falhar se este não for o caso. Para evitar problemas com as chaves
estrangeiras, tabelas devem ser seqüenciadas adequadamente no dataset.
30. Principais componentes
● IDataSet
● XmlDataSet - Lê e escreve documento XML conjunto de dados original. Este formato é
muito detalhado e deve estar em conformidade com determinado DTD:
– <!DOCTYPE dataset SYSTEM "dataset.dtd">
– <dataset>
<table name="TEST_TABLE">
<column>COL0</column> <column>COL1</column> <column>COL2</column>
<row>
<value>row 0 col 0</value> <value>row 0 col 1</value> <value>row 0 col 2</value>
</row>
<row>
<null/> <value>row 1 col 1</value><null/>
</row>
</table>
</dataset>
● Outras implementaçães: StreamingDataSet, XlsDataSet, QueryDataSet, ...
31. Principais componentes
● DatabaseOperation
● DatabaseOperation.DELETE
– Esta operação apaga somente o conteúdo do dataset. Esta operação
não apaga o conteúdo da tabela inteira, mas somente os dados que
estão presentes no dataset.
● DatabaseOperation.DELETE_ALL
– Exclui todas as linhas das tabelas presentes no dataset. Se o conjunto
de dados não contém uma tabela em particular, mas essa tabela existe
no banco de dados, a tabela de banco de dados não é afetado. Tabelas
são truncados na sequência inversa.
● DatabaseOperation.TRUNCATE
– Truncar tabelas presentes no dataset especificado. Comportamento
semelhante ao DELET_ALL
32. Seam e DBUnit
● O seam prover uma classe de utilidade
(DBUnitSeamTest) que facilita a construção
de testes de integração com de componentes
Seam e dados gerados no formato DBUnit.
● DBUnitSeamTest
● Subclasse da classe SeamTest
● Permite inserir e limpar dados no banco de dados
antes e depois de um teste
● É preciso implementar o método
prepareDBUnitOperations()
33. Principais componentes
● DatabaseOperation.CLEAN_INSERT
● Sua operação composta executa uma operação DELETE_ALL seguida
por uma operação INSERT. Esta é a abordagem mais segura para
garantir que o banco de dados está em um estado conhecido. Isto é
apropriado para testes que exigem que o banco de dados para conter
apenas um conjunto específico de dados.
● DatabaseOperation.REFRESH
● Esta operação, literalmente, refresh no conteúdo do dataset no banco
de dados alvo. Isto significa que os dados de linhas existentes são
atualizados e linhas não-existente são inseridas. Todas as linhas que
existem no banco de dados, mas não no dataset permanecem
inalteradas. Esta abordagem é mais apropriada para testes que
assumem outros dados podem existir no banco de dados.
34. Seam e DBUnit
● Exemplo
● public class MyTest extends DBUnitSeamTest {
protected void prepareDBUnitOperations() {
beforeTestOperations.add(
new DataSetOperation("/datasets/AppData.xml",
DatabaseOperation.INSERT)
); }
... // métodos @Test
}
35. Jboss Embedded
● É uma API capaz de executar o Kernel do
Jboss 5 e serviço JEMS como class loader
non-JBoss-controlled.
● Isso significa que é capaz de rodar o Jboss na
mesma JVM como um programa java simples,
ou como um teste com Junit, ou mesmo operar
como um servidor de aplicação.
36. Observação
● Apartir da JDK 6 update 4, o JAXB teve sua
obrigatoriedade foi retirada da JDK.
● O Jboss Embedded, utilizado pelo Seam nos
tetes de integração tem problemas de
compatibilidade com a JDK 6, que pode ser
resolvida adicionando um argumento na JVM
quando da compilação e execução do Jboss
Embedded.
● -Dsun.lang.ClassLoader.allowArraySyntax=true
37. Exercicios
● Objetivo agora é implementar todos os testes
de integração que estejam faltando no projeto
“ponto”.