4.3 Testando cenários mais complexos
Vamos agora começar a testar nosso LeilaoDao. Um dos métodos desse DAO retorna a quantidade de leilões que ainda não foram encerrados. Veja:
public Long total() {
return (Long) session.createQuery("select count(l) from "+
"Leilao l where l.encerrado = false")
}
Ele faz um simples SELECT COUNT. Para testar essa consulta, adicionaremos dois leilões: um encerrado e outro não encerrado. Dado esse cenário, esperamos que o método total() nos retorne 1. Vamos ao teste.
Repare que, para criar um Leilão, precisaremos criar um Usuário e persisti-lo no banco também, afinal o Leilão referencia um Usuário; para fazer
isso, utilizaremos o UsuarioDao, que sabe persistir um Usuario!
Essa é uma das dificuldades de se escrever um teste de integração: montar cenário é mais difícil. Dê uma olhada no código a seguir, ele é extenso, mas está comentado:
public
class LeilaoDaoTests { private Session session; private LeilaoDao leilaoDao; private UsuarioDao usuarioDao;
@Before
public void antes() {
session = new CriadorDeSessão().getSession(); leilaoDao = new LeilaoDao(session); usuarioDao = new UsuarioDao(session);
}@After
public void depois() { session.close();
}
@Test
public void deveContarLeiloesNaoEncerrados() {
// criamos um usuario Usuario mauricio =
new Usuario("", "mauricio@aniche.com.br");
// criamos os dois leiloes Leilao ativo =
new Leilao("Geladeira", 1500.0, mauricio, false); Leilao encerrado =
new Leilao("XBox", 700.0, mauricio, false); encerrado.encerra();
// persistimos todos no banco usuarioDao.salvar(mauricio); leilaoDao.salvar(ativo); leilaoDao.salvar(encerrado);
// invocamos a a�ao que queremos testar
// pedimos o total para o DAO long total = leilaoDao.total();
assertEquals(1L, total);
}
}
Se rodarmos o teste, ele passa!
Mas esse teste ainda não está legal. Nesse momento, ele passa porque estamos rodando-o usando o banco de dados HSQLDB. Se estivéssemos rodando em um MySQL, por exemplo, esse teste poderia falhar. Cada vez que rodamos o teste, ele insere 2 linhas no banco de dados. Se rodarmos o teste 2 vezes, por exemplo, teremos 2 leilões não encerrados, o que faz com que o teste falhe:
A melhor maneira de garantir que, independente do banco em que você esteja rodando o teste, o cenário esteja sempre limpo para aquele teste. É ter a base de dados limpa. Um jeito simples de fazer isso é executar cada um dos testes dentro de um contexto de transação e, ao final do teste, fazer um “rollback. Com isso, o banco rejeitará tudo o que aconteceu no teste e continuará limpo.
Isso é fácil de ser implementado. Basta mexermos nos métodos @Before
e After:
@Before
public void antes() {
session = new CriadorDeSessão().getSession(); leilaoDao = new LeilaoDao(session); usuarioDao = new UsuarioDao(session);
// inicia transa�ao session.beginTransaction();
}
@After
public void depois() {
// faz o rollback session.getTransaction().rollback(); session.close();
}
Pronto. Agora, mesmo no MySQL, esse teste passaria. Iniciar e dar rollback na transação durante testes de integração é prática comum. Faça uso do @Before e @After para isso, e dessa forma, seus testes ficam independentes e fáceis de manter.
Usar ou não usar HSQLDB?
Os desenvolvedores se dividem muito entre usar HSQLDB ou o banco de produção nos testes. A vantagem do HSQLDB é clara: o teste roda muito mais rápido, afinal ele é um banco de dados em memória, muito mais leve.
No entanto, sou mais favorável a testes de integração que realmente façam uso do mesmo banco que a aplicação que será usada em produção. Apesar dos testes ficarem mais lerdos, o feedback é maior. Na prática, sabemos que algumas consultas SQL são dependentes de banco, e que, em um caso extremo, o resultado pode ser diferente.
Portanto, se estou pagando o custo de fazer um teste de integração, prefiro que ele seja o mais real possível.