【问题标题】:Testing Hibernate Envers测试休眠环境
【发布时间】:2018-06-29 18:40:08
【问题描述】:

我想编写有关修订的测试。在控制台中,我看到了 Hibernate 的更新调用,但没有插入 AUD-Table。

测试方法:

@DataJpaTest
class JPAHistoryTest {

    @Test
    public void test() {
        def entity = // create Entity
        def entity2 = // create same Entity
        entity2.setPrice(entity2.getPrice() + 10)
        entity2.setLastUpdate(entity2.lastUpdate.plusSeconds(10))

        service.save(entity)
        service.save(entity2)
        repository.flush() // Hibernate updates changes

        assert repository.findRevisions(entity.id).content.empty == false // FAIL!
    }
}

我的实体看起来像:

@Entity
@Audited
class Entity {
    @Id @GeneratedValue Long id
    @Column(nullable = false) BigDecimal price
}

非常感谢。

【问题讨论】:

    标签: hibernate testing junit hibernate-envers


    【解决方案1】:

    我发现我保留@DataJpaTest 并添加@Transactional(propagation = NOT_SUPPORTED) 以确保测试方法不会启动事务。因为如果它们将在事务中运行,那么当测试关闭事务时,将写入 envers 历史条目。

    @RunWith(SpringRunner)
    @DataJpaTest
    @Transactional(propagation = NOT_SUPPORTED)
    class JPAHistoryTest {
        @After
        void after() {
            repository.deleteAll()
        }
    
        @Test
        public void testTwoInsert() {
            def entity1 = // ...
            def entity2 = // ...
    
            sut.save(entity1 )
            sut.save(entity2 )
    
            assert repository.findRevisions(entity1.id).content.size() == 1
            assert repository.findRevisions(entity2.id).content.size() == 1
        }
    }
    

    【讨论】:

      【解决方案2】:

      我发现了和你一样的问题并尝试了@michael-hegner 的答案,但是我使用了TestEntityManager 类,所以当没有交易时我无法获得EntityManagerpropagation 设置为NOT_SUPPORTED)。

      在我的情况下,解决方案是从 TestEntityManager 手动提交事务,首先保存实体和更改,然后再查询修订。

      这是一个测试类:

      @DataJpaTest
      class UserRepositoryTest {
      
          @Autowired
          private TestEntityManager testEntityManager;
      
          @Test
          public void shouldBeAudited() {
              User user = getTestUser();
              testEntityManager.persistAndFlush(user);
      
              user.setPassword("tset");
              testEntityManager.merge(user);
      
              // This line is critical here to commit transaction and trigger audit logs
              testEntityManager.getEntityManager().getTransaction().commit();
      
              // With propagation = NOT_SUPPORTED this doesn't work: testEntityManager.getEntityManager()
              AuditReader auditReader = AuditReaderFactory.get(testEntityManager.getEntityManager());
              List revisions = auditReader.createQuery()
                      .forRevisionsOfEntity(User.class, true)
                      .add(AuditEntity.id().eq(user.getId()))
                      .getResultList();
      
              assertEquals(1, revisions.size());
          }
      
          private User getTestUser() {
              User user = new User();
              user.setUsername("test");
              user.setEmail("test");
              user.setPassword("test");
              return user;
          }
      
      }
      

      在测试之后手动删除用户可能是强制性的,因为事务已提交,而在其他测试中它可能会导致一些问题。

      【讨论】:

      • 非常感谢。 testEntityManager.getEntityManager().getTransaction().commit(); 是一条神奇的线,它让 Envers 触发审计查询。
      【解决方案3】:

      老实说,我在这里不遵循您的命名约定。通常,service 方法调用由生产代码中的一些事务上下文包装。

      @Service
      public class Service1 {
        @Transactional
        public void save(Object object) {
        }
      }
      
      @Service
      public class Service2 {
        @Transactional
        public void save(Object object) {
        }
      }
      

      对于需要在单个事务上下文中绑定两个服务方法调用的情况,您可以通过另一个服务调用来包装这两个单独的服务。

      @Service
      public class ServiceWrapper {
        @Autowired
        private Service1 service1;
        @Autowired
        private Service2 service2;
      
        @Transactional
        public void save(Object object1, Object object2) {
          service1.save( object1 );
          service2.save( object2 );
        }
      }
      

      重要的是要指出这个ServiceWrapper 不一定必须存在于您的生产代码中。该 bean 可能是您专门为测试而创建的。关键是这个 bean 以非常类似于 Spring 的方式构建,以满足您需要的事务边界。

      现在在您的测试中,您可以使用 repository 来查找实体,因为包装器内的事务提交数据,从而可以按预期在 Envers 审计表中进行查找。

      @Test
      public void testSomething() {
        Object entity1 = //
        Object entity2 = //
        serviceWrapper.save( entity1, entity2 );
      
        // now use the repository to find the entity revision
      }
      

      【讨论】:

      • 嗨,Naros,感谢您的回复,我会试试看。
      • 嗨,Naros,抱歉回复晚了。关键是,数据通过 Spring-Integration 通道逐个进入服务,每个数据都在其事务中。完成后,历史记录条目将被写入数据库,正如我在事务关闭时所知道的那样。 DataJpaTest 包含 Transactional,因此我的测试方法启动事务,并在执行测试用例后关闭。但是我想要验证的历史条目尚不可用。我的最终解决方案我将在上面编辑我的答案。谢谢。
      • 我们在 Envers 测试套件中做了类似的事情;但是,我们有一个特殊的注释,它强制@Test 方法的优先执行顺序,以便数据插入方法首先发生,然后我们的附加注释测试方法独立执行。
      【解决方案4】:

      如果您不想像 Michael Hegner 的回答那样更改整个测试类的事务行为,您可以执行以下操作:

      @RunWith(SpringRunner)
      @DataJpaTest
      class JPAHistoryTest {
      
          @Autowired
          private MyRepository repository;
          @Autowired
          private PlatformTransactionManager platformTransactionManager;
      
          @After
          void after() {
              repository.deleteAll()
          }
      
          @Test
          public void testTwoInsert() {
              TransactionTemplate tx = new TransactionTemplate(platformTransactionManager);
              tx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
      
              def entity1 = // ...
              def entity2 = // ...
      
              tx.execute(status -> repository.save(entity1))
              tx.execute(status -> repository.save(entity2))
      
              assert repository.findRevisions(entity1.id).content.size() == 1
              assert repository.findRevisions(entity2.id).content.size() == 1
          }
      }
      

      因此,使用PROPAGATION_NOT_SUPPORTED 创建一个TransactionTemplate 并使用该交易模板进行保存。这也会触发正在保存的审计信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-27
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多