Borba on Software Desenvolvendo Software com Qualidade.

11Sep/082

DbUnit x Hibernate

testingAqui na empresa, temos clientes que apenas mandam executar um projeto segundo a arquitetura definida por eles. Algumas vezes é frustante trabalhar neste tipo de projeto, afinal, nem sempre conseguimos seguir nossas convicções e utilizar plenamente nossos conhecimentos e experiência na definição da melhor solução para o problema. Em um desses projetos, fui convocado para auxiliar a equipe que estava consumindo muito tempo na implementação dos testes.

O Cenário:

O sistema utiliza EJB 2 e Hibernate 2. O cliente exige implementação de testes dos métodos da fachada utilizando JUnit e DbUnit.

Problemas:

A montagem dos cenários é complexa. O DbUnit entende apenas o modelo relacional, isto significa que o engenheiro tem que fazer um "desmapeamento hibernate" na cabeça dele para montar as tabelas e colunas com os valores necessários. Veja um exemplo:

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <employee start_date="2001-01-01"
              first_name="Drew"
              ssn="333-29-9999"
              last_name="Smith" />

    <employee start_date="2002-04-04"
              first_name="Nick"
              ssn="222-90-1111"
              last_name="Marquiss" />

    <employee start_date="2003-06-03"
              first_name="Jose"
              ssn="111-67-2222"
              last_name="Whitson" />
</dataset>

Claro que esse é um modelo relacional simples, agora imagine modelos de classes complexos, com heranças, relacionamentos, etc. Neste caso, dá bastante trabalho.

Além da dificuldade em produzir a massa de dados, existe um problema muito grave. Dentro das classes de teste é necessário fazer validações contra os valores do arquivo xml (por exemplo em métodos de consulta). Neste caso podemos fazer as validações com valores hard coded, como neste exemplo:

assertEquals(employee.getFirstName(), "Jose");

Que é uma péssima idéia, pois viola o princípio DRY (Don't Repeat Yourself). Outra saída é obter os valores do xml através da API do DbUnit, que vai dar uma trabalheira danada, ainda mais se você quiser montar o objeto para fazer comparações deste tipo:

assertEquals(employeeActual, employeeExpected);

Já imaginou? Vai ter que construir outro hibernate só para pegar cada valor das tabelas e colunas do arquivo XML e remontar os objetos novamente.

Como Resolver?

O grande problema dessa abordagem é o fato do DbUnit entender apenas de tabelas e colunas. E se existisse um HibernateUnit? No hipotético HibernateUnit eu poderia especificar meus dados na forma de objetos. Além disso, poderia utilizar um formato mais legível e que pudesse ser transformado diretamente para objetos dentro do seu código. Esse formato pode ser o YAML. Veja como ficaria:

departaments:
    - &engineering
      id          : 1
      name        : Engineering
      employees:
    - id          : 1
      startDate   : 2001-01-01
      firstName   : Drew
      lastName    : Smith
      ssn         : 333-29-9999
      departament : *engineering
    - id          : 2
      startDate   : 2002-04-04
      firstName   : Nick
      lastName    : Marquiss
      ssn         : 222-90-1111
      departament : *engineering
    - id          : 3
      startDate   : 2003-06-03
      firstName   : Jose
      lastName    : Whitson
      ssn         : 111-67-2222
      departament : *engineering

Inclui um relacionamento para employee só para ficar um pouco mais rico. A vantagem dessa abordagem é que além de ficar mais legível, existem frameworks que serializam e deserializam esse formato para objetos. Com esse recurso, seria possível obter os objetos diretamente do arquivo e em seguida fazer comparações com objetos obtidos no banco. Legal, hein?

Acho que uma solução deste tipo poderia trazer muitos benefícios para o nosso problema. Estou fazendo uma pesquisa e se não existir nada semelhante, devo implementar essa solução como um projeto open source.

Pena que nosso cliente EXIGE que usemos o DbUnit.

Comments (2) Trackbacks (0)
  1. Não dá para criar uma implementação do IDataSet do DbUnit para carregar arquivos YAML? Alias, outro formato interessante para os datasets seria JSON, que conta com o suporte bastante amadurecido do XStream: http://xstream.codehaus.org/json-tutorial.html

    No mais, a violação do DRY não chega a ser tão critica porque para mim, em testes, a legibilidade sobre a “situação testada” (o testcase) tem mais importância do que o DRY: http://blog.jayfields.com/2008/05/testing-duplicate-code-in-your-tests.html

    Abraço…

  2. Vamos por partes… Sobre a implementação de IDataSet utilizando YAML já existe (http://jyaml.sourceforge.net/yaml4dbunit.html), porém eu não acho interessante porque de qualquer forma você vai estar definindo um dataset relacional e não objetos. Sobre o JSON, acho interessante sim, tive uma certa dificuldade em conseguir boas implementações YAML para java.

    Sobre a violação do DRY, no caso que eu descrevi ela é nociva mesmo porque o “Jose” é só um nome que tem que necessariamente estar igual ao que coloquei no dataset (este é o objetivo do teste).


Leave a comment

(required)

No trackbacks yet.