数据库单元测试框架?

时间:2011-08-04 12:02:22

标签: java unit-testing spring jpa dbunit

在我的项目中,我使用了spring,jpa和PostgreSQL DB, 我在DB中有很多表,我需要对所有这些表进行单元测试。

是否有任何框架在每次测试完成后回滚所有事务,因此每个测试都会有新的/相同的DB数据进行测试。这种方式在所有测试执行之后,数据库模式的数据将保持不变。

对此有何建议?

我对DBUnit有所了解,但我需要为每个测试编写每个输入数据的.xml文件,需要在setup()中插入数据并清除/删除tearDown()中的数据,但不是对我来说似乎是更好的策略。

任何建议表示赞赏。 感谢。

4 个答案:

答案 0 :(得分:4)

正如@Ryan表示......应该咨询Testing section of the Spring Reference manual

一些启动提示......

我们使用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() {
    }

}

请注意:

  1. 并非所有测试类都需要额外的上下文,跳过特定子类的@ContextConfiguration
  2. 我们通过ant执行并使用forkmode="perBatch"任务上的junit属性。这可确保所有测试都使用相同的上下文配置运行(从每次测试的重新加载Spring上下文中省去)。您可以使用@DirtiesContext指示应在方法/类之后刷新上下文。
  3. 使用@Test注释标记每个方法。 Spring框架没有使用Junit的public void testXXX()约定来获取方法。

答案 1 :(得分:3)

  

是否有任何框架在每次测试完成后回滚所有事务,因此每个测试都会有新的/相同的DB数据进行测试。这种方式在所有测试执行之后,数据库模式的数据将保持不变。

从当天早些时候发布的my other answer开始,是的,这可以使用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方法中使用setup可确保清除文件中指定的所有表(通过删除所有行),然后在测试数据文件中插入指定的数据。

避免使用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中使用dbdeploy,但这主要是为了使测试数据库与版本化数据模型保持同步。

答案 2 :(得分:2)

Spring's test framework完全适合你。

答案 3 :(得分:0)

我按照方式处理了它。

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

希望有所帮助

<强>更新

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

  • 运行bootstraping数据脚本以提交数据
  • 从DB中检索所有人并在其上断言。喜欢明智地看到所有的CRUD

回滚您可以标记的交易

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)

所以它会回滚数据库的东西