【问题标题】:Integration testing with Hibernate Envers使用 Hibernate Envers 进行集成测试
【发布时间】:2012-01-11 22:11:04
【问题描述】:

我正在尝试围绕一些经过审计的实体构建一些测试。我的问题是 envers 只审核事务提交。

我需要创建/编辑一些测试对象,提交事务,然后检查修订。

使用 envers 进行集成测试的最佳方法是什么?

更新:这是我想要实现的一个非常糟糕的、不确定的测试类。我宁愿这样做而不依赖于测试方法的顺序

首先在单个事务中创建一个帐户和 account_transaction。两个经审核的条目均适用于修订版 1。

第二次更新了新交易中的 account_transaction。经审核的条目为第 2 版。

第三,在修订版 1 中加载经过审计的帐户并对其进行处理。

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/testApplicationContext.xml"})
public class TestAuditing {

    @Autowired
    private AccountDao accountDao;

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    @Rollback(false)
    public void first() {
        Account account = account("Test Account", "xxxxxxxx", "xxxxxx");

        AccountTransaction transaction = transaction(new Date(), Deposit, 100, "Deposit");
        account.setTransactions(newArrayList(transaction));

        accountDao.create(account);
    }

    @Test
    @Rollback(false)
    public void second() {
        Account account = accountDao.getById(1L);
        AccountTransaction transaction = account.getTransactions().get(0);
        transaction.setDescription("Updated Transaction");
        accountDao.update(account);
    }

    @Test
    public void third() {
        AuditReader reader = AuditReaderFactory.get(entityManager);

        List<Number> accountRevisions = reader.getRevisions(Account.class, 1L);
        //One revision [1]

        List<Number> transactionRevisions = reader.getRevisions(AccountTransaction.class, 1L);
        //Two revisions [1, 2]

        Account currentAccount = accountDao.getById(1L);
        Account revisionAccount = (Account) reader.createQuery().forEntitiesAtRevision(Account.class, 1).getSingleResult();

        System.out.println(revisionAccount);
    }

【问题讨论】:

  • 检查this out - 无耻的自我推销。
  • 感谢 Tomasz 的回复,不过我仍然不确定如何从您的博客文章中解决我的问题。我对延迟加载等误报并没有真正的问题,更多的是实际提交一些事务来设置一些审计测试数据。也许我错过了你帖子中明显的一些东西?
  • 好吧,将我的文章向下滚动到DbResetRule - 我的想法是避免使用@Transactional JUnit 测试,而让您的代码提交和回滚事务。显然,这使得测试不可重复且脆弱。但是,我建议在每次测试之前/之后转储数据库并恢复它,而不是回滚更改。代码在 Scala 中,但这只是一个一般性的想法。让我知道这是否是您正在寻找的东西,所以我将在单独的答案中详细说明。
  • 当您使用@Transactional 注释方法时,您无需手动执行任何操作。看起来你已经在这样做了。但是当你从测试中删除@Transactional 时,你不能简单地在测试中使用EntityManager。要么将其访问封装在事务性 bean 中,要么使用 TransactionTemplate
  • 太棒了,正是我需要的。已添加我的代码作为答案。

标签: hibernate jpa-2.0 integration-testing hibernate-envers


【解决方案1】:

根据 Tomasz 的建议,我使用 TransactionTemplate 来实现每次 dao 操作后的提交。没有类级别的@Transactional 注解。

envers 审计条目是在方法完成之前插入的,这正是我所需要的。

@ContextConfiguration("testApplicationContext.xml")
public class TestAuditing extends AbstractJUnit4SpringContextTests {

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Autowired
    private PersonDao personDao;

    private TransactionTemplate template;

    @Before
    public void transactionTemplate() {
         template = new TransactionTemplate(platformTransactionManager);
    }

    @Test
    public void test() {
        Person person = createInTransaction(person("Karl", "Walsh", address("Middle of nowhere")), personDao);
        System.out.println(person);
    }

    private <T> T createInTransaction(final T object, final Dao<?, T> dao) {
        return template.execute(new TransactionCallback<T>() {
            public T doInTransaction(TransactionStatus transactionStatus) {
                dao.create(object);
                return object;
            }
        });
    }
}

【讨论】:

    【解决方案2】:

    我是 Spring 事务测试支持的用户,它在测试完成后回滚测试,并且由于环境设计,不会创建修订。我创建了一个 hack,它似乎允许人们在事务提交之前手动“告诉”envers 完成其工作,但允许 spring 继续回滚。

    这些 sn-ps 应该会有所帮助。 1. 创建您自己的审计监听器,覆盖现有的 envers 审计监听器。这允许访问对单元测试可见的静态成员。可能有更好的方法,但它确实有效。

    public class AuditEventListenerForUnitTesting extends AuditEventListener {
    
       public static AuditConfiguration auditConfig;
    
       @Override
       public void initialize(Configuration cfg) {
          super.initialize(cfg);
          auditConfig = super.getVerCfg();
       }
    }
    

    修改您的 persistence.xml 以包含这个新的侦听器类,而不是 envers 提供的类

    (如有必要,对其他听众重复)

    现在在“单元”测试中:

    {
       saveNewList(owner); //code that does usual entity creation
       em.flush();  
       EventSource hibSession = (EventSource) em.getDelegate();
       AuditEventListenerForUnitTesting.auditConfig.getSyncManager().get(hibSession).doBeforeTransactionCompletion(hibSession);     
       //look for envers revisions now, and they should be there
    }
    

    我需要这个,因为我有一些针对连接到版本控制表的休眠实体的 JDBC 查询。

    【讨论】:

      【解决方案3】:

      其他两个解决方案对我不起作用,所以我使用了另一种方法,我只是创建一个新事务并强制提交。每次我需要一个新的修订版时,我都会再做一次。

      @Autowired
      @Qualifier("transactionManager")
      private PlatformTransactionManager platformTransactionManager;
      
      @Test
      public void enversTest() throws Exception{
          Entity myEntity = new Entity();
      
          TransactionStatus status = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
          myEntity.setName("oldName");
          myEntity = entityDao.merge(myEntity);
          platformTransactionManager.commit(status); // creates a revision with oldname
      
          TransactionStatus newStatus = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
          myEntity.setName("newName");
          myEntity = entityDao.merge(myEntity);
          platformTransactionManager.commit(newStatus); // creates a new revision with newName
      }
      

      如果您使用@Transactional(transactionManager="transactionManager"),但它可能会绕过提交并将每个测试视为一个事务(因此不会在同一个测试中进行多次版本控制...)

      【讨论】:

        【解决方案4】:

        这受到 this previous answer 的强烈启发,适用于 Envers 4.2.19.Final (JPA 2.0)。此解决方案也不需要提交事务,这在我的案例中是一个要求。

        首先创建org.hibernate.integrator.spi.Integrator的以下实现并将其添加到类路径中:

        public class MyIntegrator implements Integrator {
        
          public static AuditConfiguration auditConfig;
        
          @Override
          public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {
            auditConfig = AuditConfiguration.getFor(configuration);
          }
        
          @Override
          public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {
            // NOP
          }
        
          @Override
          public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
            // NOP
          }
        
        }
        

        然后在src/test/resources 下创建一个META-INF/services/org.hibernate.integrator.spi.Integrator 文件并将集成器类的完全限定名称粘贴到其中。

        在您的测试中,调用您的 DAO 方法,刷新休眠会话,完成后告诉 Envers 继续:

        EventSource es = (EventSource) entityManager.getDelegate();
        SessionImplementor si = entityManager.unwrap(SessionImplementor.class);
        MyIntegrator.auditConfig.getSyncManager().get(es).doBeforeTransactionCompletion(si);
        

        然后您可以测试数据库的内容并最终回滚事务。

        【讨论】:

          【解决方案5】:

          为 Envers 5.4.15.Final 更新了 @thomas-naskali's answer 版本

              protected void flushEnvers()
              {
                  final EventSource eventSource = entityManager.unwrap(EventSource.class);
                  final Session session = entityManager.unwrap(Session.class);
                  final SessionImplementor sessionImplementor = entityManager.unwrap(SessionImplementor.class);
          
                  final EnversService service = session.getSessionFactory()
                      .getSessionFactoryOptions()
                      .getServiceRegistry()
                      .getService(EnversService.class);
          
                  service.getAuditProcessManager().get(eventSource)
                      .doBeforeTransactionCompletion(sessionImplementor);
              }
          

          【讨论】:

          • 这个!我需要添加 session.flush() 来获得我需要的行为,但是这个。
          猜你喜欢
          • 2011-07-05
          • 1970-01-01
          • 2018-04-18
          • 2013-04-07
          • 2019-12-17
          • 2015-12-28
          • 2020-05-26
          • 2018-01-02
          • 2021-02-03
          相关资源
          最近更新 更多