Дублирование идентификатора с использованием JPA2 и тестирование - PullRequest
0 голосов
/ 16 декабря 2010

Я сейчас немного запутался: -S

Я работаю над проектом, который использует JPA2, Spring 3.0.5, Hibernate 3.6.0 Final. У нас есть следующий код (только соответствующие классы)

@Entity
public class User extends AbstractEntity implements Serializable {
    @Id
    @Column(name = "ID", nullable = false, insertable = true, updatable = true, length = 36)
    protected String id;

    @NotNull
    @Size(min = 1, max = 30)
    @Column(name = "NAME", length = 30, nullable = false)
    private String name;

    protected User() {
        id = java.util.UUID.randomUUID().toString();
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof User)) {
            return false;
        }
        User other = (User) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }


}


@Repository("userDao")
public class UserDaoImpl implements UserDao {

    @PersistenceContext
    private EntityManager em;

    public void create(User user) throws PreexistingEntityException, Exception {
        try {
            em.persist(user);

        } catch (EntityExistsException ex) {
            logger.error("User " + user + " already exists.", ex);
            throw new PreexistingEntityException("User " + user + " already exists.", ex);
        } catch (Exception ex) {
            logger.error("Exception occurred:", ex);
            throw ex;
        }
    }
}



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/testDaoContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class UserDaoTest {

    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Test
    public void testInsertUserExistingID() {
        User user = User.valueOf("1");
        user.setFirstname("DUMMY");
        user.setName("CRASH");
        logger.debug(user);
        try {
            userDao.create(user);
            sessionFactory.getCurrentSession().flush();
        } catch (PreexistingEntityException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.debug("id = " + user.getId());

        User retrieved = userDao.find(user.getId());
        Assert.assertEquals(user.getId(), retrieved.getId());
        Assert.assertEquals("DUMMY", retrieved.getFirstname());
        Assert.assertEquals("CRASH", retrieved.getName());
    }

}

Теперь, когда я запускаю тест (я знаю, что это не настоящий модульный тест) с откатом, установленным в false, я получаю следующую трассировку стека:

org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into PV_UMDB.USERS (CREATION_DT, CREATION_USR, MODIFICATION_USR, MODIFICATION_DT, VERSION, BIRTHDAY, EMAIL, FAX, FIRSTNAME, INTERNAL, MOBILE, NAME, PHONE, PICTURE, STAFF_NO, STAFF_NO_KBC, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [PV_UMDB.USERS_PK]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:471)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:515)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:290)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:183)
    at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:90)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
    ... 25 more
Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (PV_UMDB.USERS_PK) violated

    at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10768)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    ... 34 more

Если я использую откат, то тест проходит успешно, что, конечно, неверно.

Теперь, есть ли хорошее решение?

Спасибо за вашу помощь

BB Питер

Ответы [ 2 ]

1 голос
/ 16 декабря 2010

Вы не можете положиться на EntityExistsException, брошенный persist().

Из Javadoc :

EntityExistsException - если субъект уже существует. (Если субъект уже существует, EntityExistsException мая быть брошенным, когда упорная операция вызывается, или EntityExistsException или другой PersistenceException может быть брошено в сброс или фиксация времени. )

В вашем случае вы получаете другое исключение во время фиксации. Если вы замените

sessionFactory.getCurrentSession().flush();

с

em.flush();

вы можете поймать PersistenceException брошенный во время сброса (я не уверен, почему он не работает так же с SessionFactory).

0 голосов
/ 17 декабря 2010

Тест состоит в том, чтобы увидеть, если пользователь с существующий идентификатор сохраняется, Выдается исключение PreexistingEntityException.

Общий шаблон проверки исключения:

  • Junit4: @Test (excpect = ExcpectedException.class) или
  • JUnit3 или когда не работает простой шаблон:

Псидокод для JUnit3

try { 
  invokeExceptionThrowingMethod();
  fail("ExceptionX expected");
} catch(ExcpectedException e) {
  //expected - do nothing
}

Я твердо верю, что если вы напишите свой тестовый пример более понятным, чем вы найдете ошибку.

изм

В вашем случае вам нужен второй вариант, потому что тест не должен принимать исключение из первого создания пользователя.

@Test
public void testInsertUserExistingID()         
       //(See my comment to your question about throwing Exception)
       throws Exception{
    User user = User.valueOf("1");
    user.setFirstname("DUMMY");
    user.setName("CRASH");

    try {
        userDao.create(user);
        sessionFactory.getCurrentSession().flush();
        fail("PreexistingEntityException expected");
    } catch (PreexistingEntityException e) {
        //Thats what is execpected
    }
}

В любом случае: акставт прав

...