Testes com JUnit + HSQLDB

Hoje fiz uma experiência legal no projeto em que estou trabalhando.

Estou há um tempinho bolando uma forma razoável para testar a aplicação de cabo a rabo. A única coisa que eu ainda não estava convencido totalmente sobre como fazer era testar as classes DAO ou fazer testes envolvendo elas.

Já lí em alguns lugares algumas pessoas falando que os testes não devem utilizar o banco de dados por uma série de motivos e que os DAOs sempre devem ser mocks. Até eu mesmo já cheguei a questionar se isso é realmente necessário. Depois de um tempinho com a idéia fermentando na cabeça eu penso o seguinte:

Primeiro: É interessante testar os DAOs porque você precisa garantir por exemplo que todos os campos estão sendo lidos corretamente para os objetos e que as queries funcionam. No caso de utilização de JPA/Hibernate ainda te ajuda a validar se o mapeamento objeto-relacional está correto.

Segundo: Existem alguns tipos de testes que podem ser feitos na sua aplicação. Se falarmos de teste unitário eu concordo que não deve haver utilização de banco de dados mas sim mocks para os DAOs e tudo mais que não for objeto do teste em questão. Porém para testes de integração ou aceitação é desejável que o banco de dados seja incluído no teste já que faz parte da aplicação.

Mas o problema de envolver o BD nos testes é que eles (os testes) ficam muito lentos e isso desfavorece o desenvolvimento guiado por testes, que eu não vivo sem. Se os testes demoram eles são executados menos vezes e isso não é bom. Sem contar que se os dados do banco forem modificados os testes quebram. Argh!

Eis que surge o HSQLDB. O HSQLDB é um banco de dados escrito em Java puro, tem driver JDBC que funciona direitinho e entende comandos SQL com JOINs, GROUP BYs e praticamente tudo mais que você utiliza numa aplicação que utiliza o banco de dados de forma NORMAL (normal = não utiliza aquelas tosqueiras proprietárias do BD que depois que se usa não dá mais para trocar nem a versão do bicho!).

O que eu fiz foi fazer com que os testes se conectassem num HSQLDB ao invés do banco de dados de desenvolvimento. Para melhorar, esse HSQLDB não está nem rodando em modo server em lugar nenhum. Ele é iniciando junto com os testes e roda em memória na mesma JVM que os testes rodam.

Quais foram os ganhos obtidos com este approach:

1) Minhas queries agora estão sendo testadas, assim como a criação dos meus objetos pelos DAOs.

2) Os testes estão muito rápidos, nem parece que usam banco de dados! Eu tinha criado duas suites de testes, uma que tinha testes com BD e outra sem BD. Isso nem será mais necessário agora.

3) Agora eu tenho a garantia de que os dados de teste não serão modificados e com isso os testes não quebrarão mais por este motivo. Sabendo que os dados não mudarão posso fazer testes mais completos e elaborados.

Porém também experimentei alguns pontos negativos:

1) Qualquer alteração de modelo tem que ser refletida no script de startup do HSQLDB. O script de startup é necessário para indicar quais tabelas com quais campos e dados ele criará em memória. São CREATE TABLEs com duas ou três coisinhas a mais, muda pouca coisa.

2) Em algumas aplicações que eu trabalho tem lógica da query no hint!!! Isso acontece porque lá na empresa tem um trilhão de aplicações rodando em produção no mesmo Oracle que eu rodo minha aplicação. Sendo assim se eu faço uma query ferrada eu derrubo o banco e junto com ele uma boa parte da empresa. Para evitar que isso aconteça os DBAs otimizam uma boa parte das queries que fazemos, só que as vezes a coisa fica tão dramática que os DBAs têm que fazer MAGIAS no hint para a query executar num tempo razoável. Aí eles mexem tanto no hint que no final a query depende do hint para funcionar, quando o hint deveria ser só para ela ficar mais rápida. Aí fica assim: com o hint a query retorna o resultado de um jeito e sem hint de outro! Como hint é coisa do Oracle e o HSQLDB entende como comentário, eventualmente não será possível testar uma ou outra query porque no HSQLDB o resultado será retornado sem executar a lógica contida no raio do hint!

Vou evoluir mais em cima desta idéia e na medida que as coisas forem acontecendo eu posto aqui mais comentários.

Tags: , , , , ,

No Responses to “Testes com JUnit + HSQLDB”

  1. É isso aí, agora só falta a gente arranjar um modo de testar aquele que não podemos falar o nome :P

  2. A gente também tem testado com os Daos de verdade, usamos ou o hsqldb, ou o h2 ou ainda o derby. No @Before sempre damos um SchemaExport pra zerar todas as tabelas e os testes rodarem isolados.

    Parabéns pelo post

  3. Basta lembrar que você “deve” (hehehe) estar usando uma camada de indireção como um framework ORM neste caso (deixa eu adivinhar, tá usando Hibernate?). Quando você trabalha com Plain Old JDBC DAOs e como quase sempre usar SQL ANSI não é opção este problema piora bastante.

    Outro ponto negativo é que você pode ter problemas específicos de plataforma, problemas que funcionam no banco de verdade e falham no de teste ou, pior, vice-versa.

    Ter um SGBD em memória pode ser legal para testar durante o desenvolvimento mas uma suite de testes automatizada utilizando um mecanismo de integração continua e o banco ‘de verdade’ é crucial.

  4. COM CERVEJA. Concordo plenamente. O objetivo deste approach não é substituir o banco de dados em todos os testes, mas sim passar a testar mais coisas só que utilizando um banco de dados fake para garantir dados consistentes, banco sempre online e velocidade. Como vc falou mesmo.

  5. Julierme says:

    Gostei muito, continue com o alto nivel de publicações.

  6. Ednelson says:

    Guilherme, antes de mais nada, gostaria de parabenizá-lo pelo nível das publicações, fica bem explícito aqui que estes posts são frutos de pesquisa, experiência e um pouco do sofrimento peculiar a vida de desenvolvedor : ) . Brincadeiras a parte, vc recomenda alguma bibliografia sobre testes na camada de persistência? Quais?

  7. Oi Ednelson. Infelizmente não tenho nenhuma bibliografia específica para recomendar sobre este assunto. Porém na revista Mundo Java deste mês (número 23) saiu uma matéria sobre “Testes unitários para camadas de negócios”. Só vou ler a revista no fim de semana, portanto ainda não posso dizer se o artigo está bom ou não. Mas vale dar uma olhada, pode ser que te dê alguma idéia.

    Abraços,
    Guilherme

  8. Marcos Silva Pereira says:

    Um detalhes sobre bancos em memoria que passa despercebido é o fato de eles não precisarem de setup manual, o que elimina conversas do tipo:
    - Na minha maquina os testes funcionam normalmente.
    - Na minha não! Qual será o problema?

    É importante que os testes sejam tão independentes de setup quanto possivel.

    valeuz…

  9. Ednelson says:

    Guilherme, apenas registrando aqui, encontrei algum material no serverside http://www.theserverside.com/tt/articles/article.tss?l=PersistentDomain
    , que por sua vez foi extraído do Pojo in Action. Só mais uma pergunta, no Mustang jah vem embutido o derby, vc usou este banco neste contexto, caso afirmativo percebeu alguma vantegem?

  10. Olha, eu não conheço nada em relação do Derby. Vou procurar saber e de repente posto um tópico aqui sobre o assunto :)
    Abraços,
    Guilherme

  11. Rodrigo Veiga says:

    Interessante esse seu post. Nossa equipe está começando a experimentar o TDD aqui em um dos projetos, mas algumas questões já surgem: os testes envolverão a camada de persistência? envolverão a camada de apresentação? que ferramentas utilizaremos? Junit puro, Cactus, JWebUnit? Vou considerar a opção de usar o HSQLDB em memória (seria algo como um “Mock Database”). Pretendo pesquisar para ver se há alguma opção de banco “lightweight” com maior compatibilidade com o “SQL Oracle”.

Leave a Reply