2010-12-16 21 views
0

我有點糊塗了現在:-S副本ID使用JPA2和測試

我正在使用JPA2,春季3.0.5項目的Hibernate 3.6.0決賽。我們有以下的代碼(僅適用於相關的類)

@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 彼得

+0

究竟是什麼問題,什麼是預期的行爲?另外'User.valueOf()'是什麼意思? – axtavt 2010-12-16 13:30:42

+0

@axtavt:問題是,我認爲我應該得到的異常(PreexistingEntityException)由於其AOP而被Spring所吃掉,因此我的測試本身是無用的。 valueOf()方法是一種返回具有特定ID的對象的方法,因爲通常ID是UUID。 – 2010-12-16 14:17:05

+0

@Peter:你如何在測試中獲得'SessionFactory'? – axtavt 2010-12-16 14:34:43

回答

1

你不能依靠EntityExistsException通過persist()拋出。

javadoc

EntityExistsException - 如果實體 已經存在。 (如果實體已經 存在,EntityExistsException可以 拋出時persist操作 被調用時,或 EntityExistsException或另一 PersistenceException可以在 沖洗被拋出或提交時間。

在你的情況,你會得到另一個在提交時拋出的異常。如果您有

em.flush(); 

更換

sessionFactory.getCurrentSession().flush(); 

你能趕上在沖水時間(我不知道爲什麼它不與SessionFactory相同的方式工作)拋出PersistenceException

+0

+1找到原因 – Ralph 2010-12-17 11:27:11

0

測試是看是否與現有 ID的用戶被存儲,則 PreexistingEntityException被拋出。

用於檢查異常的一般模式是:

  • Junit4:@Test(excpect = ExcpectedException.class),或
  • JUnit3或者當容易圖案不工作:

psydocode爲JUnit3

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

我強烈地相信,如果你寫得更清楚你的測試用例,你會發現這個bug。

編輯

在你的情況,你需要的第二個變體,因爲測試不能接受來自第一用戶創建一個例外。

@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 
    } 
} 

反正:axtavt是正確