仅为创建和清理数据库设置一次以测试所有DAO

时间:2011-09-27 07:12:21

标签: hibernate spring testing maven-2 junit4

是否有人知道如何实现以下用于测试DAO的流程:

  • 运行SQL脚本以创建通用数据库设置(将数据插入所有表)
  • 测试DAO1
  • 测试DAO2
  • ...
  • 清理步骤1中创建的数据库

使用Spring,Hibernate,JUnit,Maven堆栈。

据我所知,最佳实践是我们为每个测试DAO(@BeforeClass)创建数据,并在完成所有测试后(@AfterClass)清理相同的数据。

但是在我们的例子中,不同数据库表之间存在太多依赖关系(客户端的遗留数据库:(目前无法做任何事情)。用测试数据填充每个表需要许多其他表中的数据因此,为每个DAO单独创建数据将非常困难且耗时。因此,我们确实只需要创建一次DB测试数据。

我使用BaseDAO中的静态块创建了测试数据(由每个DAO测试类扩展) - 显然只运行一次。但是当所有测试(所有DAO测试子类)完成时,如何清理相同的问题。在DAO Test类完成后,每次都会运行基类中的@AfterClass拆解方法。

请告知。

6 个答案:

答案 0 :(得分:3)

如果你正在使用Maven,一个不错的选择是使用DBUnit。它允许您从数据库导出测试数据(或只是用XML编写),以便为测试导入。它有Maven plugin,可以满足您的需求。

答案 1 :(得分:1)

在春季3:

<jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:schema.sql"/>
    <jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>

Documentation。要在测试后清理数据库,请创建一个仅在测试期间拾取的Spring bean:

@Service
public class DbCleanup {
    @Resource
    private DataSource ds;

    @PreDestroy
    public cleanUpDb() {
        //do your cleanup with DB
    }
}

答案 2 :(得分:1)

我使用以下解决方案。

(1)我有一个名为Fixture的简单界面

package com.obecto.fixtures;

public interface Fixture {

    void prepare();

}

(2)我准备一个SQL fixture来填充一个空数据库 - 这可以通过实体或像这样执行SQL来完成:

package com.avaco2.fixtures;

import java.util.logging.Logger;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;

import com.obecto.fixtures.Fixture;

@Component(value="logEventsSQLFixture")
public class LogEventsSQLFixture implements Fixture {
    private static String IMPORT_SQL = "import-LogEvents.sql";
    private static Logger LOG = Logger.getLogger(LogEventsSQLFixture.class.getName());

    @Autowired
    private BasicDataSource dataSource;

    @Override
    public void prepare() {
        SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);
        Resource sqlScript = new ClassPathResource(IMPORT_SQL);
        try {
            SimpleJdbcTestUtils.executeSqlScript(jdbcTemplate, sqlScript, true);
        } catch (Exception e) {
            LOG.severe("Cannot import " + IMPORT_SQL);
        }

    }

}

(3)将您的灯具注入Test类,prepare - 将它们注入@Before - 方法。

始终使用其他数据库进行测试,因此您可以安全地使用hibernate的 create-drop 设置。要在每个测试方法之前重新加载上下文,您可以使用以下注释 - @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)

答案 3 :(得分:1)

没有人建议为每个测试使用@Transactional属性进行注释。如果db引擎支持它,那应该负责回滚状态。有关详情,请参阅herestackoverflow link

答案 4 :(得分:0)

通常我备份整个数据库实例(实际上我正在使用Oracle和imp / exp是很棒的工具)。 SQL Server和相似的都有复制方法。准备好数据后,只需导出整个实例并在测试前加载它。

测试完成后,删除数据库并重新创建。 (使用本机程序转储和加载整个数据库可能比预期的更快)

此致

PS:如果可以,只需在虚拟机上构建克隆数据库,然后在虚拟机中保存快照(以便稍后恢复)。

答案 5 :(得分:0)

您还可以使用数据库模型工具,例如Acolyte(https://github.com/cchantep/acolyte),在这种情况下,您无需清理数据,确保哪些数据可用于哪个JDBC进行哪些测试,而无需更改JDBC基于您想要测试的代码。

注意:我是Acolyte的作者。