Hibernate 仅为测试所有DAO创建和清理一次DB设置

Hibernate 仅为测试所有DAO创建和清理一次DB设置,hibernate,spring,testing,maven-2,junit4,Hibernate,Spring,Testing,Maven 2,Junit4,是否有人知道实现以下DAO测试流程的方法: 运行SQL脚本创建公共数据库设置(将数据插入所有表) 测试DAO1 测试DAO2 清理步骤1中创建的数据库数据 使用Spring、Hibernate、JUnit、Maven堆栈 我知道最佳实践是为每个测试DAO(@BeforeClass)创建数据,并在所有测试完成后清理数据(@AfterClass) 但是在我们的例子中,不同的数据库表之间存在太多的依赖关系(客户机的遗留数据库:-(目前对此无能为力)。用测试数据填充每个表也需要许多其他表中的数据。

是否有人知道实现以下DAO测试流程的方法:

  • 运行SQL脚本创建公共数据库设置(将数据插入所有表)
  • 测试DAO1
  • 测试DAO2
  • 清理步骤1中创建的数据库数据
使用Spring、Hibernate、JUnit、Maven堆栈

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

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

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


请告知。

通常我会备份整个db实例(实际上我正在使用Oracle和imp/exp,它们是很好的工具)。SQL Server和alikes有复制方法。一旦您准备好数据,只需导出整个实例并在测试前加载即可

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

问候

PS:如果可以,只需在虚拟机上建立一个克隆数据库,然后在虚拟机上保存一个快照(以便以后可以还原它)。

在Spring 3中:

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

如果您使用的是Maven,一个很好的选择就是使用它。它允许您从数据库导出测试数据(或仅用XML编写),以便为您的测试导入数据。它有一个可以满足您需要的功能。

我使用以下解决方案

(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) 将夹具注入测试类,并在
@Before
-方法中准备它们


始终使用另一个数据库进行测试,这样您就可以安全地使用hibernate的create drop设置。要在每个测试方法之前重新加载上下文,您可以使用以下注释-
@DirtiesContext(classMode=classMode.AFTER\u每个\u测试\u方法)

没有人建议为每个测试使用@Transactional属性进行注释。如果db引擎支持它,则应负责回滚状态。有关此方面的详细信息,请参阅或。

您也可以使用db实体模型工具,如Acolyte()在这种情况下,您不需要清理数据,确保哪些数据在哪个JDBC中可用于哪个测试,而无需更改要测试的基于JDBC的代码


注意:我是Acolyte的作者。

不确定maven是否是一条可行之路。有时,在执行每个测试方法之前,您需要准备DB。使用maven是否可以实现这一点?好的,您是对的。问题的具体内容是只准备一次。是的。我们使用JUnit
@MethodRule
(或JUnit 4.9中的
@TestRule
),它在每个测试方法之前设置数据库,然后进行清理。无论如何,OP已经在使用Maven,并且要求数据库设置围绕整个测试阶段,而不是问题中所述的测试方法。啊,刚刚收到您的下一条消息:)@Cities,不要将高代表性用户标记为垃圾邮件。他们显然贡献了其他工作。垃圾邮件会受到惩罚。我们宁愿教育人们如何自我宣传,而不是惩罚他们。
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);
        }

    }

}