如何使用Spring Test在每个案例中加载一次DBUnit测试数据

时间:2010-06-09 15:43:02

标签: junit dbunit spring-test

Spring Test有助于回滚在测试方法中对数据库所做的任何更改。这意味着在每种测试方法之前没有必要花时间删除/重新加载测试数据。

但是如果使用@BeforeClass Junit注释,则会强制数据加载器保持静态。这里探讨了一个问题:Why must jUnit's fixtureSetup be static?

如果数据初始化方法是静态的,那么数据连接方法和数据源也必须......以及......强制一切都是静态的......这是行不通的。在这一点上,我问 - 当你必须为每次测试删除/重新加载测试数据时,Spring Test能够回滚更改的能力??!?!

5 个答案:

答案 0 :(得分:14)

一种方法是创建“数据初始化”类,将其添加到也具有数据源的测试Spring应用程序上下文,并将此应用程序上下文连接到测试中。这依赖于Spring在测试调用之间缓存应用程序上下文的事实。

例如,测试超类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:test-application-context.xml"})
@Transactional
public abstract class DataLoadingTest {
    @Autowired
    protected DatabaseInitialiser databaseInitialiser;
}

使用test-application-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dataSource" .../>

    <bean class="DatabaseInitialiser">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

public class DatabaseInitialiser extends JdbcDaoSupport {
    @PostConstruct
    public void load() {
        // Initialise your database here: create schema, use DBUnit to load data, etc.
    }
}

在这个例子中:

  • 所有依赖数据库的测试都会扩展DataLoadingTest;
  • Spring在第一次测试调用时初始化应用程序上下文;
  • 通过DatabaseInitialiser.load()注释
  • 调用@PostConstruct
  • Spring将应用程序上下文保留在缓存中;
  • 来自已缓存的应用程序上下文的DatabaseInitialiser中的进一步测试调用;
  • 测试是事务性的,并在最后回滚到初始数据集。

同样,DatabaseInitialiser可以使用注释@PostDestroy的方法来执行整个测试运行结束时所需的任何回滚。

答案 1 :(得分:1)

Spring Test和DbUnit是两个优秀的框架。但是将它们组合起来没有意义。由于Spring Test在连接上执行回滚,因此它会在之后清除,而DbUnit会清除并在@Before方法中插入测试数据。

如果您不依赖于任何动态数据,请使用Spring,否则使用dbUnit。

答案 2 :(得分:1)

我们广泛使用DBUnit和Spring Test。但是我们不会在测试结束时使用DBUnit功能删除数据。

我们在@Before方法中为我们的测试数据放置了一堆DBUnit插件来初始化测试。然后,当测试完成后,我们让spring rollback功能使数据库恢复到原始状态。

我们遇到的最大问题是必须在每次测试之前加载DBUnit数据,这可能是主要的性能损失。我们使用DBUnit的大多数测试都是只读的,根据某些预定义的行为测试应用程序的行为。因此,我们习惯于创建主测试,然后在同一事务中批量运行所有细粒度测试。

答案 3 :(得分:0)

方法annotated with @BeforeTransaction在每个测试的事务开始之前运行,如其名称所示。如果在这种方法中您可以检测是否加载了测试数据,那么可以在需要时加载数据。

请注意,数据保留在(内存中)数据库中以进行所有后续测试。

我们使用它来加载“静态”数据,这些数据在生产环境中也会在启动时引导到我们的数据库中。这样我们实际上为我们的测试使用完全相同的代码和数据,而不是依赖可能过时的(DbUnit)导出。

答案 4 :(得分:0)

您可以创建一个数据初始值设定项“bean”,因为配置只运行一次。它遵循与主要答案相同的原则,但代码和类更少

@Configuration
class DBUnitTest_Config {
  protected String PATH = "";

  @Bean
  public DataSetConfig setupData(DataSource dataSource) throws SQLException {
    DataSetExecutorImpl executor = DataSetExecutorImpl.instance(new ConnectionHolderImpl(dataSource.getConnection()));
    DataSetConfig dataSetConfig = new DataSetConfig(PATH);
    executor.createDataSet(dataSetConfig);
    return dataSetConfig;
  }

}