【问题标题】:Unittest a transactional method with REQUIRES_NEW and always force rollback使用 REQUIRES_NEW 对事务方法进行单元测试并始终强制回滚
【发布时间】:2014-04-01 08:16:06
【问题描述】:

我想测试一个通过在循环中调用 DAO 将数据插入表中的服务方法。服务方法用

注释
@Transactional(propagation = Propagation.REQUIRES_NEW)

单元测试调用服务方法并用

注释
@Transactional

现在我想告诉事务它总是应该在最后进行回滚。我不想在测试运行后手动清理数据库。

@Rollback 和 EntityManager.getTransaction().setRollbackOnly() 不起作用。我认为原因是注释和 setRollbackOnly() 仅应用于由测试方法创建的事务,而不应用于由服务方法创建的事务。

有人知道怎么解决吗?

【问题讨论】:

  • 模拟DAO,手动将其注入到新构建的服务中,并测试方法。您不需要 Spring 上下文或事务来对服务进行单元测试。
  • 这就是我现在正在做的事情。但无论如何,我还是想知道是否可以将事务设置为rollbackonly。
  • 如果你这样做,你就不需要回滚任何东西,因为你不会有事务。 new Service(mockDao).callMethod() 不启动事务,所以没有什么可以回滚的。
  • 请尽量以科学的方式理解问题。我不需要解决方案来继续我的工作。我只是想知道这是否可能,以及 - 如果可以的话,我该怎么做。
  • 可以做什么?回滚不存在的事务?不,这是不可能的。

标签: spring jpa junit spring-transactions


【解决方案1】:

我认为不可能轻松回滚 REQUIRES_NEW 事务。 SpringTest 启动一个事务,它可以回滚它启动的事务。但不是内部开始的交易。

因此,您可能会退回到 REQUIRED 或编写测试以正常工作,即使它们已提交。如果选择后者,可以通过randomization实现测试隔离。

【讨论】:

    【解决方案2】:

    您可能可以创建org.springframework.transaction.PlatformTransactionManager 的可控模拟实现,将其委托给真实的实现,唯一的区别是它可以选择将新事务标记为只读。如果使用基于 java 的上下文配置,类似的情况:

    ...
    public class DaoTest {
    ...
    @Autowired
    Dao _dao;
    @Autowired
    MockPlatformTransactionManager _transactionManager;
    ...
    @Test
    @Transactional
    public void testSomeAction() throws Exception
    {
        try (AutoCloseable ignored = _transactionManager.withRollBack())
        {
            _dao.someAction();
        }
    }
    ...
    interface MockPlatformTransactionManager extends PlatformTransactionManager
    {
        AutoCloseable withRollBack();
    }
    ...
    // Somewhere in the @Configuration class
    @Bean
    MockPlatformTransactionManager transactionManager()
    {
        // an instance of real TM is adapted to become a MockPlatformTransactionManager 
        return new MockPlatformTransactionManager()
        {
            private final PlatformTransactionManager _delegate = 
                // TODO: same transaction manager as before
                new DataSourceTransactionManager(dataSource());
            private boolean shouldRollBack = false;
    
            @Override
            public TransactionStatus getTransaction(final TransactionDefinition definition)
                throws TransactionException
            {
                final TransactionStatus transaction = _delegate.getTransaction(definition);
                if (shouldRollBack)
                    transaction.setRollbackOnly();
                return transaction;
            }
    
            @Override
            public void commit(final TransactionStatus status) throws TransactionException
            {
                _delegate.commit(status);
            }
    
            @Override
            public void rollback(final TransactionStatus status) throws TransactionException
            {
                _delegate.rollback(status);
            }
    
            @Override
            public AutoCloseable withRollBack()
            {
                shouldRollBack = true;
                return new AutoCloseable()
                {
                    @Override
                    public void close() throws Exception
                    {
                        shouldRollBack = false;
                    }
                };
            }
        };
    }
    

    【讨论】:

      【解决方案3】:

      如果您使用允许设置 UserTransaction 的 PlatformTransactionManager 实现(如 org.springframework.transaction.jta.JtaTransactionManager),您可以实例化一个 UserTransaction 实现,该提交方法执行回滚。

      import com.atomikos.icatch.jta.UserTransactionImp;
      
      @Bean
      public UserTransaction myUserTransaction() {
          final UserTransactionImp userTransactionImp = new UserTransactionImp() {            
      
              @Override
              public void commit() throws javax.transaction.RollbackException, javax.transaction.HeuristicMixedException,
                      javax.transaction.HeuristicRollbackException, javax.transaction.SystemException, java.lang.IllegalStateException,
                      java.lang.SecurityException {
                  rollback();
              }
          };
      
          return userTransactionImp;
      }
      

      然后,在您的 PlatformTransactionManager bean 中:

      @Bean
      public PlatformTransactionManager transactionManager(
              @Qualifier("myUserTransaction") UserTransaction myUserTransaction,
              @Qualifier("myTransactionManager") TransactionManager myTransactionManager
      ) {
      
          final JtaTransactionManager jtaTm = new JtaTransactionManager();
      
          jtaTm.setTransactionManager(myTransactionManager);
          jtaTm.setUserTransaction(myUserTransaction);
      
          return jtaTm;
      }
      

      我还让我的 dao 不会产生任何同花顺。

      【讨论】:

        猜你喜欢
        • 2012-10-14
        • 2016-06-29
        • 2012-06-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-21
        • 1970-01-01
        • 1970-01-01
        • 2021-09-16
        相关资源
        最近更新 更多