Java DB单元测试框架?

Java DB单元测试框架?,java,unit-testing,spring,jpa,dbunit,Java,Unit Testing,Spring,Jpa,Dbunit,在我的项目中,我使用了spring、jpa和PostgreSQL DB, 我有很多数据库中的表,我需要对它们进行单元测试 是否有任何框架可以在每个测试完成后回滚所有事务,以便每个测试都有新的/相同的DB数据进行测试。这样,在所有测试执行之后,DB模式的数据将保持原样 有什么建议吗 我对DBUnit有一些概念,但在这方面,我需要为每个测试的每个输入数据编写.xml文件,并且需要在setup()中插入数据,在tearDown()中清除/删除数据,但对我来说,这似乎不是更好的策略 如有任何建议,我们将

在我的项目中,我使用了spring、jpa和PostgreSQL DB, 我有很多数据库中的表,我需要对它们进行单元测试

是否有任何框架可以在每个测试完成后回滚所有事务,以便每个测试都有新的/相同的DB数据进行测试。这样,在所有测试执行之后,DB模式的数据将保持原样

有什么建议吗

我对DBUnit有一些概念,但在这方面,我需要为每个测试的每个输入数据编写.xml文件,并且需要在setup()中插入数据,在tearDown()中清除/删除数据,但对我来说,这似乎不是更好的策略

如有任何建议,我们将不胜感激。
谢谢。

我已经按照以下方式处理了

当项目处于测试模式时。我使用bootstraping数据使用
dbdeploy
修复了可以断言的数据。并直接使用
dao
测试应用程序的dao和DB层

希望能有帮助

更新

例如,在您的系统中有一个名为
Person
的实体,现在您可以测试基本的CRUD操作

  • 运行引导数据脚本来加载数据
  • 从数据库中检索所有人员并对其进行断言。像智者一样看到所有的积垢
要回滚事务,可以标记

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
因此,它将回滚DB内容

是否有任何框架可以在每个测试完成后回滚所有事务,以便每个测试都有新的/相同的DB数据进行测试。这样,在所有测试执行之后,DB模式的数据将保持原样

从当天早些时候发布的消息来看,是的,这可以使用DbUnit实现。(根据您的编辑,您不需要这个;我的回答的后续部分将说明我为什么使用DbUnit,以及何时不使用它)

以下代码段演示了如何执行每个测试的设置:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    IDatabaseConnection connection = null;
    try
    {
        connection = getConnection();
        IDataSet dataSet = getDataSet();
        //The following line cleans up all DbUnit recognized tables and inserts and test data before every test.
        DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    }
    finally
    {
        // Closes the connection as the persistence layer gets it's connection from elsewhere
        connection.close();
    }
}

private IDatabaseConnection getConnection() throws Exception
{
    @SuppressWarnings({ "rawtypes", "unused" })
    Class driverClass = Class.forName("org.apache.derby.jdbc.ClientDriver");
    Connection jdbcConnection = DriverManager.getConnection(jdbcURL, "XXX",
            "YYY");
    IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
    return databaseConnection;
}

private IDataSet getDataSet() throws Exception
{
    ClassLoader classLoader = this.getClass().getClassLoader();
    return new FlatXmlDataSetBuilder().build(classLoader.getResourceAsStream("database-test-setup.xml"));
}
database test setup.xml
文件包含每次测试将插入数据库的数据。在
设置
方法中使用
DatabaseOperation.CLEAN_INSERT
可确保清除文件中指定的所有表格(通过删除所有行),然后在测试数据文件中插入指定数据

避免DbUnit

我使用上述方法专门在每个测试开始之前清除序列,因为应用程序使用JPA提供程序在单独的事务中更新序列。如果您的应用程序没有执行类似的操作,那么您只需在
setup()
方法中启动一个事务,并在测试结束后发出一个回滚。如果我的应用程序没有使用序列(如果我不想重置序列),那么我的设置例程将非常简单:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    // emf is created in the @BeforeClass annotated method
    em = emf.createEntityManager();
    // Starts the transaction before every test
    em.getTransaction.begin();
}

@After
public void tearDown() throws Exception
{
    logger.info("Performing the teardown of test {}", testName.getMethodName());
    if (em != null)
    {
        // Rolls back the transaction after every test
        em.getTransaction().rollback();
        em.close();
    }
}

另外,我使用Maven,但这主要是为了使测试数据库与版本化数据模型保持最新。

正是为您这样做的。

正如@Ryan所指出的。。。。应咨询专家

一些启动提示

我们使用Spring的
AbstractTransactionalJUnit4SpringContextTests
处理了这个问题

例如,我们定义了一个抽象超类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:WebContent/WEB-INF/testconfig/test-web-application-config.xml")
@TransactionConfiguration()
@Transactional
public abstract class OurAbstractTransactionalSpringContextTest extends AbstractTransactionalJUnit4SpringContextTests {
}
然后需要额外上下文的单个子类被定义为:

@ContextConfiguration("classpath:path/to/config/ConfigForTestCase.xml")
public class TestOurFunction extends OurAbstractTransactionalSpringContextTest {
    @Test
    public void testOurMethod() {
    }

}
请注意:

  • 并非所有测试类都需要额外的上下文,请跳过特定子类上的
    @ContextConfiguration
  • 我们通过ant执行,并在junit任务上使用
    forkmode=“perBatch”
    属性。这确保所有测试都以相同的上下文配置运行(避免为每个测试重新加载Spring上下文)。您可以使用
    @DirtiesContext
    指示应该在方法/类之后刷新上下文
  • @Test
    注释标记每个方法。Spring框架不会使用Junit的
    public void testXXX()
    约定获取方法

  • 通过这种方式,由于数据未在数据库中提交,因此不会测试数据的持久性,并且可能不会引发一些违反约束的异常等。因此,这种与事务相关的方法似乎并不适合所有场景。您的意思是说,在不提交事务的情况下会引发违反约束的异常?如果是,我真的不知道这一点,你能给出一些想法吗?@JigarJoshi让我们感谢你的回答,这确实非常有用,但我认为对于第一种方法(DbUnit),在安装过程中的每个测试都会有数据插入的开销()例如,在许多测试中,我们需要来自一个或两个表的数据,但每次setup()都会插入所有表的数据。我认为第二种方法(事务)不会将数据保存在DB中(它不会实际持久化数据)所以DB不会抛出违反约束的异常,而且它似乎不适合所有场景的测试。如果我在这方面有错,请告诉我。@SmartSolution,您可以始终为每个夹具提供单独的XML文件。当然,如果夹具中的每个测试只需要一部分数据,并且这是一项开销,那么我建议使用。在约束违反和抛出异常的主题中,当您刷新“持久性文本”而不是“提交”时,将抛出持久性异常。@ StaskStudio,如果不刷新持久性上下文,则考虑更改存储库/ DAO类来执行此操作。如果有一组单元测试将在普通Java SE环境中创建持久性上下文并测试DAO/存储库行为,则可以避免这种情况——这不会测试事务传播等。这是正确的,但不是非常具体。参见雅各布的详细阐述。