Тестирование исключений Junit с весенними транзакциями и откатами - PullRequest
2 голосов
/ 23 декабря 2011

Так что у меня есть интересная проблема, с которой мне понадобится помощь.Я знаю, что было задано множество вопросов об откате транзакций с использованием junit, но я считаю, что моя проблема немного отличается.Чтобы лучше понять проблему, позвольте мне начать с самого начала.

Я внедрил UserManagementService с соответствующими DAO для системы управления пользователями.Существует общий метод CreateUser (User obj), который используется для создания уникального пользователя.Теперь существует ограничение на то, что адреса электронной почты уникальны, поэтому, если мы попытаемся вызвать этот метод с адресом электронной почты, который уже был использован, мы выдадим пользовательское исключение UserManagementException с соответствующим сообщением об ошибке.Все это прекрасно работает, однако, проблема, с которой я сталкиваюсь, заключается в тестировании модулей.О, прежде чем я забуду, позвольте мне упомянуть программный стек, который я использую [ Java, Spring, Hibernate ]

У меня есть свой класс модульного теста с аннотациями Transactional для каждого метода, который на самом делепопадает в БД.Эти методы также имеют аннотацию @Rollback, так что все вставки, обновления и удаления откатываются в конце каждого вызова теста.Итак, проблема, с которой я сталкиваюсь, заключается в том, что я хотел бы протестировать сценарий с уникальным ограничением пользователя.Вызывая createUser (obj) второй раз с объектом пользователя с тем же адресом электронной почты, я хочу убедиться, что выдается исключение UserManagementException.Однако, поскольку он является транзакционным, всякий раз, когда выдается исключение, транзакция выполняет откат до завершения модульного теста и, следовательно, не проходит тест.Ниже приведен тестовый пример.

@Test
@Rollback
@Transactional
public void testUniqueCreateConsoleUser() {
    boolean success;
    ConsoleUser newUser;
    //first one
    userManagementDao.createConsoleUser(user);
    //second one. This shd throw a UserManagementException
    try {
        //now try and insert a new user with same email
        newUser = new ConsoleUser("Queen", "Kong", "king.kong@blah.com", "kingkong","Universal Studios", "America/Los_Angeles", false, null);
        userManagementDao.createConsoleUser(newUser);
        //if this passed this is a problem. Console users should have unique email address
        success = false;
    } catch (UserManagementException e) {
        success = true;
    }
    Assert.assertTrue(success);
}

Странно то, что когда я запускаю его через отладчик, метод Assert.assertTrue () вызывается корректно, но в конечном итоге тест завершается неудачей.

Еще я попробовал добавить опору в аннотацию @Transactional.Я добавил текущую @ Transactional (noRollbackFor = UserManagementException.class) в надежде, что, если возникнет исключение, откат не будет вызван тогда, но в конце теста.Возможно, я подхожу к этому неверно, поэтому любые идеи или лучшие практики, касающиеся такого рода тестирования, будут высоко оценены.

Примечание. Ниже приведен фрагмент трассировки стека.

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:695)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect

Ответы [ 3 ]

0 голосов
/ 23 декабря 2011

Вместо того, чтобы вставлять пользователя и затем вставлять другого пользователя с тем же адресом электронной почты, я предлагаю сначала загрузить существующего пользователя из базы данных, а затем попытаться вставить пыльник с тем же адресом электронной почты, который былизвлекаться.Если это так, вам просто нужно сделать:

@Test(expected = UserManagementException.class)
public void insert_duplicate_user() throws Exception {

  // Read user from database
  final ConsoleUser user = dao.load(...);

  // Create new user with same email address.
  final ConsoleUser newUser = new ConsoleUser (...);
  newUser.setEmail(user.getEmail());

  // Write
  dao.createConsoleUser(newUser);

  /*
   * If you get here, there is a problem with your DAO logic
   * and a new user (with the same email was created).
   * So, we need to clean that up
   */

  // Delete new user  
  dao.deleteUser(newUser);
}

Этот тест не пройдёт, если не будет выброшено UserManagementException.

0 голосов
/ 23 декабря 2011

Сложно понять из вашего примера, но вы, похоже, проверяете фактическую реализацию DAO. Вместо того, чтобы данные модульного теста попадали в вашу реальную базу данных, имитируйте ваш DAO либо с помощью фиктивной реализации, либо с помощью фреймворка. Затем вы можете манипулировать данными, возвращаемыми программно, и преобразовывать их в любые сценарии проверки, которые вам нужны.

0 голосов
/ 23 декабря 2011

Если вы можете подтвердить, что добавлен дополнительный откат (например, когда пружина вставляет, когда видит, что произошел сбой, она уже откатывает транзакцию?), То вам нужно откатить откат или настроить пружину не откатить транзакцию обратно.

То есть, очевидно, что откат, который реализует пружина, конфликтует с ожидаемым откатом в вашем модульном тесте. Этот откат затем запутывает аннотацию отката, вызывая непредвиденное исключение в «модульном тесте / Spring ether».

ПРОСТОЕ РЕШЕНИЕ: не включайте автоматические откаты для этого теста. Тесты не всегда должны быть идеально элегантными.

...