Интеграционное тестирование с Hibernate Envers - PullRequest
8 голосов
/ 03 декабря 2011

Я пытаюсь построить некоторые тесты вокруг некоторых проверяемых объектов.Моя проблема заключается в том, что включает только аудит для фиксации транзакции.

Мне нужно создать / отредактировать некоторые тестовые объекты, зафиксировать транзакцию и затем проверить ревизии.

Каков наилучший подход к интеграционному тестированиюwith 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);
    }

Ответы [ 4 ]

4 голосов
/ 20 июля 2012

Я являюсь пользователем поддержки тестирования транзакций Spring, которая откатывает тесты, когда они выполнены, и из-за дизайна envers ревизии не создаются.Я создал хак, который, по-видимому, позволяет «сказать» энверам выполнить свою работу вручную до совершения транзакции, но позволяет Spring продолжать откат.

Эти фрагменты должны помочь.1. Создайте свой собственный audlistener, который переопределяет существующий приемник аудита 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 к объектам гибернации, присоединенным к таблицам версий.

4 голосов
/ 04 декабря 2011

По предложению Томаша я использовал 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 голосов
/ 01 апреля 2016

Это сильно вдохновлено предыдущим ответом , адаптированным для работы с Envers 4.2.19.Final (JPA 2.0).Это решение также не требует транзакции для фиксации, что было требованием в моем случае.

Сначала создайте следующую реализацию org.hibernate.integrator.spi.Integrator и добавьте ее в classpath:

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
  }

}

затем создайте файл META-INF/services/org.hibernate.integrator.spi.Integrator в src/test/resources и вставьте в него полностью уточненное имя класса интегратора.

В своем тесте вызовите метод DAO, очистите сеанс гибернации и после того, как это будет сделано, скажите Envers toпродолжить:

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

затем вы можете протестировать содержимое вашей БД и, наконец, откатить транзакцию.

0 голосов
/ 30 марта 2016

Два других решения у меня не сработали, поэтому я воспользовался другим способом, я просто создал новую транзакцию и форсировал коммит. Каждый раз, когда мне нужна новая ревизия, я делаю это снова.

@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"), это может обойти фиксацию и рассматривать каждый тест как одну транзакцию (таким образом, не проверять версию несколько раз в одном тесте ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...