O problema com o uso de um banco de dados 'real' para teste de unidade é a configuração, remoção e isolamento dos testes. Você não precisa criar um banco de dados MySQL totalmente novo e criar tabelas e dados apenas para um teste de unidade. Os problemas com isso estão relacionados à natureza externa do banco de dados e seu banco de dados de teste está inoperante, seus testes de unidade falham. Também há problemas em garantir que você tenha um banco de dados exclusivo para teste. Eles podem ser superados, mas há uma resposta mais simples.
Zombar do banco de dados é uma opção, no entanto ele não testa as consultas reais executadas. Ele pode ser usado como uma solução muito mais simples quando você deseja garantir que os dados do DAO passem pelo sistema corretamente. Mas, para testar o próprio DAO, você precisa que algo por trás do DAO tenha os dados e as consultas sejam executadas corretamente.
A primeira coisa a fazer é usar um banco de dados em memória. O HyperSQL é uma excelente opção para isso, pois tem a capacidade de emular o dialeto de outro banco de dados - para que as pequenas diferenças entre os bancos de dados permaneçam as mesmas (tipos de dados, funções e similares). O hsqldb também possui alguns recursos interessantes para teste de unidade.
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
Isso carrega o estado do banco de dados (as tabelas, dados iniciais) do testData
arquivo. shutdown=true
desligará automaticamente o banco de dados quando a última conexão for fechada.
Usando a injeção de dependência , faça com que os testes de unidade selecionem um banco de dados diferente daquele utilizado pela produção (ou teste ou local).
Seu DAO usa o banco de dados injetado para o qual você pode iniciar testes no banco de dados.
Os testes de unidade serão parecidos com (um monte de coisas chatas não incluídas por questões de brevidade):
@Before
public void setUpDB() {
DBConnection connection = new DBConnection();
try {
conn = connection.getDBConnection();
insert = conn.prepareStatement("INSERT INTO data (txt, ts, active) VALUES (?, ?, ?)");
} catch (SQLException e) {
e.printStackTrace();
fail("Error instantiating database table: " + e.getMessage());
}
}
@After
public void tearDown() {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void addData(String txt, Timestamp ts, boolean active) throws Exception {
insert.setString(1, txt);
insert.setTimestamp(2, ts);
insert.setBoolean(3, active);
insert.execute();
}
@Test
public void testGetData() throws Exception {
// load data
Calendar time = Calendar.getInstance();
long now = time.getTimeInMillis();
long then1h = now - (60 * 60 * 1000); // one hour ago
long then2m = now - (60 * 1000 * 2); // two minutes ago
addData("active_foo", new Timestamp(then1h), true); // active but old
addData("inactive_bar", new Timestamp(then1h), false); // inactive and old
addData("active_quz", new Timestamp(then2m), true); // active and new
addData("inactive_baz", new Timestamp(then2m), false); // inactive and new
DataAccess dao = new DataAccess();
int count = 0;
for (Data data : dao.getData()) {
count++;
assertTrue(data.getTxt().startsWith("active"));
}
assertEquals("got back " + count + " rows instead of 1", count, 1);
}
E, portanto, você tem um teste de unidade que chama o DAO e está usando os dados que foram configurados em um banco de dados dinâmico que existe durante a duração do teste. Você não precisa se preocupar com recursos externos ou com o estado do banco de dados antes da execução ou com a restauração para um estado conhecido (bem, o 'estado conhecido' é 'não existe', o que é trivial para reverter).
O DBUnit pode fazer muito do que descrevi em um processo mais simples na configuração do banco de dados, na criação de tabelas e no carregamento dos dados. Se você precisar usar o banco de dados real por algum motivo, essa é de longe a melhor ferramenta a ser usada.
O código acima é parte de um projeto que eu escrevi para a prova de conceito TestingWithHsqldb on github