DBUnit é uma extensão do JUnit para facilitar os testes de integração que envolvem banco de dados. Ele irá colocar os dados em um estado conhecido antes da execução de cada teste, assim evitamos problemas que podem ocorrer caso algum cenário corrompa ou altere os dados nos casos seguintes.
A ideia é muito simples, ao invés de você escrever vários SQL com insert e delete, o que seria muito chato e, complicado de dar manutenção, iremos colocar os dados em arquivos XML. O DBUnit irá gerenciar esses arquivos, fazendo todas as operações necessárias.
Chega de conversa e vamos criar um exemplo. Para isso crie um projeto Maven com o pom.xml abaixo:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.algaworks.blog</groupId> <artifactId>artigo-teste-integracao-dbunit</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <dependencies> <!-- jUnit 4 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- Hamcrest --> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <!-- Driver JDBC do MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.28</version> <scope>test</scope> </dependency> <!-- DBUnit --> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.4.9</version> <scope>test</scope> </dependency> <!-- Necessário para o DBUnit --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.5.6</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.5.6</version> <scope>test</scope> </dependency> <!-- Núcleo do Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.1.Final</version> <scope>compile</scope> </dependency> <!-- Implementação de EntityManager da JPA --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.1.Final</version> <scope>compile</scope> </dependency> </dependencies> </project>
Neste exemplo vamos criar dois casos de teste. O primeiro irá retornar carros zero km e outro com o período informado. Veja abaixo os casos de teste:
@Test public void deveRetornarCarrosZeroKm() { List<Carro> resultado = carroDAO.buscarCarrosZero(); assertThat(resultado, hasItems(new Carro(1L), new Carro(4L))); } @Test public void deveRetornarCarrosMenosDoisAnosUso() { Integer doisAnosAntes = Calendar.getInstance().get(Calendar.YEAR) - 2; List<Carro> resultado = carroDAO.buscarCarrosComIdadeInferiorA(doisAnosAntes); assertThat(resultado, hasItems(new Carro(1L), new Carro(2L), new Carro(3L), new Carro(4L))); }
Vamos ver agora o que precisamos fazer para o DBUnit funcionar no nosso caso de teste. Primeiro vamos criar uma classe utilitária para iniciar a conexão com o banco de dados e um método que irá executar as operações SQL, como o INSERT
e DELETE
.
package com.algaworks.blog.dbunit.dao.helper; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import org.dbunit.database.DatabaseConfig; import org.dbunit.database.DatabaseConnection; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSetBuilder; import org.dbunit.ext.mysql.MySqlDataTypeFactory; import org.dbunit.operation.DatabaseOperation; public class DbUnitHelper { private Connection conexao; private DatabaseConnection conexaoDBUnit; private String xmlFolder; public DbUnitHelper(String xmlFolder) { this.xmlFolder = xmlFolder; try { Class.forName("com.mysql.jdbc.Driver").newInstance(); conexao = DriverManager.getConnection("jdbc:mysql://localhost/artigo_teste_integracao_dbunit", "root", "root"); conexaoDBUnit = new DatabaseConnection(conexao); DatabaseConfig config = conexaoDBUnit.getConfig(); config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); } catch (Exception e) { throw new RuntimeException("Erro inicializando DBUnit", e); } } public void execute(DatabaseOperation operation, String xml) { try { InputStream is = getClass().getResourceAsStream("/" + xmlFolder + "/" + xml); FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder(); IDataSet dataSet = builder.build(is); operation.execute(conexaoDBUnit, dataSet); } catch (Exception e) { throw new RuntimeException("Erro executando DbUnit", e); } } public void close() { try { conexaoDBUnit.close(); conexao.close(); } catch (SQLException e) { e.printStackTrace(); } } }
Reparou que o método execute
recebe uma String
? Esse é o nome do arquivo xml que contém os dados do banco de dados. Coloque o arquivo em src/test/resources/DbUnitXml com o conteúdo abaixo:
<?xml version="1.0" encoding="UTF-8"?> <dataset> <carro codigo="1" placa="AAA-1111" anoFabricacao="2014" /> <carro codigo="2" placa="AAA-1112" anoFabricacao="2013" /> <carro codigo="3" placa="AAA-1113" anoFabricacao="2012" /> <carro codigo="4" placa="AAA-1114" anoFabricacao="2014" /> <carro codigo="5" placa="AAA-1115" anoFabricacao="2011" /> <carro codigo="6" placa="AAA-1116" anoFabricacao="2010" /> <carro codigo="7" placa="AAA-1117" anoFabricacao="2010" /> </dataset>
Agora já podemos inicializar na classe de teste. Veja a classe completa abaixo:
package com.algaworks.blog.dbunit.dao; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import java.util.Calendar; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.dbunit.operation.DatabaseOperation; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import com.algaworks.blog.dbunit.dao.helper.DbUnitHelper; import com.algaworks.blog.dbunit.model.Carro; public class CarroDAOTest { private static DbUnitHelper dbUnitHelper; private static EntityManagerFactory factory; private EntityManager manager; private CarroDAO carroDAO; @BeforeClass public static void initClass() { dbUnitHelper = new DbUnitHelper("DbUnitXml"); factory = Persistence.createEntityManagerFactory("artigoTesteIntegracaoDbunitPU"); } @Before public void init() { dbUnitHelper.execute(DatabaseOperation.DELETE_ALL, "Carro.xml"); dbUnitHelper.execute(DatabaseOperation.INSERT, "Carro.xml"); manager = factory.createEntityManager(); this.carroDAO = new CarroDAO(manager); } @After public void end() { this.manager.close(); } @Test public void deveRetornarCarrosZeroKm() { List<Carro> resultado = carroDAO.buscarCarrosZero(); assertThat(resultado, hasItems(new Carro(1L), new Carro(4L))); } @Test public void deveRetornarCarrosMenosDoisAnosUso() { Integer doisAnosAntes = Calendar.getInstance().get(Calendar.YEAR) - 2; List<Carro> resultado = carroDAO.buscarCarrosComIdadeInferiorA(doisAnosAntes); assertThat(resultado, hasItems(new Carro(1L), new Carro(2L), new Carro(3L), new Carro(4L))); } }
Veja que antes da execução de cada teste, todos os carros são removidos e depois inseridos novamente, de uma forma muito simples, com apenas um arquivo Carro.xml. Nesse mesmo lugar inicializamos o DAO com o EntityManager
para testarmos as consultas.
Caso algum caso de teste altere o banco de dados, inserindo ou removendo dados, não irá atrapalhar em nada os outros, pois tudo sempre é refeito.
Não sei se você percebeu, mas dependendo do cenário essa exclusão e inserção pode ser muito demorada e você pode usar uma outra estratégia. Você pode simplesmente não apagar os dados entre os casos de teste e assim ganhar esse tempo mas, faça com bastante cuidado para não adicionar algum teste que possa corromper os dados.
Para aprender mais sobre JPA, Hibernate, DBUnit e jIntegrity, além de diversas outras tecnologias, conheça os cursos online da AlgaWorks, que são completos e substituem a necessidade de cursos presenciais.
Acesse ou baixe o código-fonte completo deste artigo no GitHub.
Olá,
o que você achou deste conteúdo? Conte nos comentários.