【问题标题】:Spring Transaction Management TestSpring事务管理测试
【发布时间】:2010-11-01 13:42:51
【问题描述】:

我想使用 SpringContextTests 测试我的 Dao 类。
在我的方法类中,我扩展了AbstractTransactionalJUnit4SpringContextTests,以便我的测试类与 JUnit4 集成。我还设置了配置并在@Before 中进行了初始化和数据库清理,在@After 中进行了拆卸。我的测试课效果很好。

我的问题是,当我运行我的测试类并且数据库充满了数据时,原始数据没有回滚并且我的数据库被清除了。在@Before 方法中,我清空数据库并填充数据,以为可以回滚,但事实并非如此。

任何人都可以找到一个可以在数据库中工作和回滚信息的示例。

插件:
我的测试方法中的每个数据库操作都会回滚。但是@Before方法中super.deleteFromTables("person")的执行并没有从数据库中回滚之前的所有数据。

Spring 会回滚所有 CRUD 操作,但在事务不回滚之前清理数据库。

【问题讨论】:

  • 如果你把'org.springframework.transaction'放在调试中,日志输出有什么有趣的地方

标签: java unit-testing spring testing


【解决方案1】:

您正在 tx.xml 中的 @Before 方法中执行 super.deleteFromTables。那么如果 tx 被回滚,删除的内容不会也被回滚吗?

【讨论】:

    【解决方案2】:

    感谢所有回答我问题的人。我从这些答案中学到了很多东西,但它并没有解决我的问题。
    我知道我的测试数据会进行事务管理,并且可以正常工作。
    这是我的错误。

    我忘记了有关数据库命令的课程,即当您在 DML 语句之后执行 DDL 语句时,它将自动提交事务。我在 DML 之后执行了 DDL,方法是删除所有记录,然后删除表的 ALTERAUTO_INCREMENT,其中将导致自动提交并永久删除表的所有记录。

    修复该场景解决了我的问题。

    【讨论】:

      【解决方案3】:

      我不确定你的课有什么问题。这是一个类的摘录,它可以使用 dbunit 和 spring 2.5 完成您想要的操作:

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations={
        "testContext.xml"})
      @TransactionConfiguration
      @Transactional
      public class SampleDAOTest {
      
          @Autowired
          private DataSource dataSource;
          @Autowired
          private SampleDAO sampleDAO;
      
          @Before 
          public void onSetUpInTransaction() throws Exception {
              //Populate Test data
              IDatabaseConnection dbUnitCon = new DatabaseConnection(DataSourceUtils.getConnection(dataSource), "DATASOURCE");
                  //read in from a dbunit excel file of test data
              IDataSet dataSet = new XlsDataSet(new File("src/test/resources/TestData.xls"));
              DatabaseOperation.INSERT.execute(dbUnitCon, dataSet);
          }
      
      
          @Test
          public void testGetIntermediaryOrganisation() {
      
              // Test getting a user
              User object = sampleDAO.getUser(99L);
              assertTrue(object.getValue);
      
      
          }
      }
      

      这种方法的好处之一是您不需要扩展任何类。因此,您仍然可以拥有自己的测试层次结构。

      如果你真的想坚持你当前的方法而不是使用 @before 注释,我认为你需要覆盖下面的方法并将你的设置代码放在那里。

      @Override
      public void onSetUpInTransaction() throws Exception {...}
      

      希望对你有帮助

      【讨论】:

        【解决方案4】:

        据我所知,通过查看 AbstractJUnit4SpringContextTests 和 TransactionalTestExecutionListener 的 Javadocs 和源代码,您需要使用 @Transactional 注释您想要事务化的测试方法。

        还有@BeforeTransaction 和@AfterTransaction 注释,您可以更好地控制事务中运行的内容。

        我建议您创建带有所有这些注释的方法,包括@Before,然后在这些方法处使用断点运行测试。这样,您可以查看堆栈并确定 spring 是否为您启动了事务。如果您在堆栈中看到类似“TransactionInterceptor”的内容,或者名称中包含“Transaction”的任何其他内容,那么您很可能正在进行交易。

        【讨论】:

          【解决方案5】:

          可能的原因:

          • 您使用的数据库/数据库引擎没有适当的事务;
          • 您正在使用多个事务管理器和/或数据源,但未选择正确的一个;
          • 您正在测试类中进行自己的独立事务

          举个例子,这是一个(我的头顶,未编译)

          public class DBTest extends AbstractTransactionalJUnit4SpringContextTests {
          
              @Autowired
              private SomeDAO _aBeanDefinedInMyContextFile;
          
              @Test
              public void insert_works() {
                  assert _aBeanDefinedInMyContextFile.findAll() == 0;
                  _aBeanDefinedInMyContextFile.save(new Bean());
                  assert _aBeanDefinedInMyContextFile.findAll() == 1;
              }
          
          
          }
          

          关键点:

          • SomeDAO 是一个接口,对应于在我的上下文中声明的 bean;
          • bean 没有任何事务性设置(建议/程序化),它依赖于事务性调用者 - 生产中的服务或我们情况下的测试;
          • 测试不包括任何事务管理代码,因为它全部在框架中完成。

          【讨论】:

          • 我的 DAO 实现扩展了 Spring 提供的 SimpleJdbcDaoSupport,以便更轻松地访问数据库。我的 DAO 有事务管理代码吗?如果我的 DAO 有事务管理,我该如何测试它?
          • 默认情况下不应该有。为 Spring 启用调试日志以查看更多信息。
          【解决方案6】:

          虽然我同意这个家伙建议使用 deciated db 进行测试,但没有任何理由为什么使用填充的 db 不起作用,@Before 和 @After 方法都是在事务上下文中执行的,因此有应该回滚更改。

          可能性:

          • 数据设置正在执行非事务性操作(即 DDL 语句)
          • 测试中的某些内容实际上是在提交事务

          您能否发布@Before 方法,我只是想知道您是在清除表格还是实际上删除并重新创建它们?

          【讨论】:

          • 我使用Spring提供的测试机制。在我的@Before 方法中,super.deleteFromTables("members");``super.executeSqlScript("classpath:somescript.sql",true);
          【解决方案7】:

          同意 Confusion——您应该针对他们自己的数据库模式运行测试。

          有了这个,你可以将你的休眠属性设置为'create-drop':

          使用 create-drop,数据库模式 将被丢弃时 SessionFactory 已显式关闭。

          见:Optional Hibernate Config properites

          示例 sn-p:

          <bean id="sessionBean" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
              <property name="dataSource" ref="dataSource"/>
              <property name="hibernateProperties">
                <props>
                  <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
                   ...etc
          

          【讨论】:

            【解决方案8】:

            回避您的问题,我建议您使用单独的数据库实例来运行您的测试。这样,您就可以安全地将其擦干净,并让您的测试根据需要对其进行初始化。

            据我所知,用于数据库测试的 Spring 支持类仅回滚测试中发生的事情,而不是在测试的设置和拆卸中发生的事情。

            【讨论】:

              猜你喜欢
              • 2022-01-24
              • 1970-01-01
              • 1970-01-01
              • 2015-07-16
              • 2013-06-30
              • 2017-05-29
              • 2012-10-16
              相关资源
              最近更新 更多