Junit 如何使用Spring测试在每个情况下加载DBUnit测试数据一次

Junit 如何使用Spring测试在每个情况下加载DBUnit测试数据一次,junit,dbunit,spring-test,Junit,Dbunit,Spring Test,SpringTest有助于回滚测试方法中对数据库所做的任何更改。这意味着在每个测试方法之前,无需花费时间删除/重新加载测试数据 但是如果使用@BeforeClass Junit注释,则会强制数据加载程序是静态的。这里探讨的一个问题是: 如果数据初始化方法是静态的,那么数据连接方法和数据源也必须是静态的。而且,不断地……强制所有内容都是静态的……这是行不通的。在这一点上,我要问-当您必须为每个测试删除/重新加载测试数据时,Spring测试回滚更改的能力有什么好处 Spring测试和DbUnit是两

SpringTest有助于回滚测试方法中对数据库所做的任何更改。这意味着在每个测试方法之前,无需花费时间删除/重新加载测试数据

但是如果使用@BeforeClass Junit注释,则会强制数据加载程序是静态的。这里探讨的一个问题是:


如果数据初始化方法是静态的,那么数据连接方法和数据源也必须是静态的。而且,不断地……强制所有内容都是静态的……这是行不通的。在这一点上,我要问-当您必须为每个测试删除/重新加载测试数据时,Spring测试回滚更改的能力有什么好处

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


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

我们广泛地将DBUnit与Spring测试结合使用。但是我们不使用DBUnit功能在测试结束时删除数据

我们在@Before方法中为测试数据插入了一组DBUnit插入,以初始化测试。然后,当测试完成时,我们让spring回滚功能将数据库恢复到其原始状态


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

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

例如,测试超类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:test-application-context.xml"})
@Transactional
public abstract class DataLoadingTest {
    @Autowired
    protected DatabaseInitialiser databaseInitialiser;
}
使用
测试应用程序上下文.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>
在本例中:

  • 所有依赖于数据库的测试都会扩展
    DataLoadingTest
  • Spring在第一次测试调用时初始化应用程序上下文
  • 这将通过
    @PostConstruct
    注释调用
    DatabaseInitialiser.load()
    
  • Spring将应用程序上下文保存在缓存中
  • 进一步的测试调用从已经缓存的应用程序上下文连接到
    数据库初始化器
    
    
  • 测试是事务性的,并在最后回滚到初始数据集
同样地,
DatabaseInitialiser
可以有一个带注释的方法
@postdirection
,以在整个测试运行结束时执行任何必要的回滚。

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

不过要注意,数据会留在(内存中)数据库中,以供后续所有测试使用


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

您可以创建一个数据初始值设定项“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;
  }

}

我发现DBUnit从XML加载数据库表的能力非常方便。弹簧测试有这样的功能吗?是的,我认为垫子是错的。从XML文件加载测试数据对使用Spring进行db测试是一个很好的好处。事实上,这正是我解决问题的方法,我只是忘记了将代码/答案放回SO中。谢谢你花时间为下一个家伙做这件事。听起来不错,但实际上另一个类的“@PostConstruct”在数据库初始化器之前运行,所以它没有用。谢谢你的帮助。@united expression:你能详细介绍一下吗?你指的是哪一类?在我的示例中,Spring在测试类之前初始化数据库初始化器,测试类在问题中概述的Cass中工作。我有另一个由Spring管理的类,由'@Component'注释,它的'@PostConstruct'方法访问数据库,以便在数据库初始化器之前初始化该类。目前的解决方法是为另一个类使用自定义注释,但更倾向于使用更好的解决方案。谢谢。我喜欢你的方法,我更进一步了。看看下面……这是一个坏习惯。你觉得这个检查过的解决方案怎么样?
@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;
  }

}