0

試圖在彈簧啓動時針對JPA圖層執行測試分片,每個guide但驗證約束似乎不會觸發。我的設置如下春季啓動測試期待ConstraintViolationException但收到JpaSystemException

@SpringBootApplication 
public class MyApplication { 

    public static void main(String[] args) { 
     SpringApplication.run(MyApplication.class, args); 
    } 
} 

@Configuration 
@EnableAutoConfiguration 
@EnableJpaRepositories(basePackages = "com.myapp.core.dao") 
@EntityScan(basePackages = {"com.myapp.core.entity"}) 
    public class CoreConfig { 
} 

@Entity 
@Table(name = "users") 
public class Users implements Serializable { 

    private static final long serialVersionUID = 1L; 
    @Id 
    @NotNull 
    @Size(min = 1, max = 50) 
    @Column(name = "username") 
    private String username; 

    ... 
} 


public interface UsersDAO extends CrudRepository<Users, String> { 
} 


@RunWith(SpringRunner.class) 
@DataJpaTest 
@AutoConfigureTestDatabase(replace=Replace.NONE) 
public class UsersDAOIT { 

    @Autowired 
    private UsersDAO usersDAO; 

    private static final String USER_NAME = RandomStringUtils.randomAlphabetic(50); 
    private static final String PASSWORD = RandomStringUtils.randomAlphabetic(50); 

    private Users p; 

    @Before 
    public void onStartUp() { 
     p = new Users(); 
     p.setUsername(USER_NAME); 
     p.setPassword(PASSWORD); 
     p.setEnabled(Boolean.TRUE); 
    } 

    @Test(expected = ConstraintViolationException.class) 
    public void testSave_NullUsername() { 
     p.setUsername(null); 
     usersDAO.save(p); 
    } 
} 

與所有的設置,測試結果如下:

java.lang.Exception: Unexpected exception, expected<javax.validation.ConstraintViolationException> but was<org.springframework.orm.jpa.JpaSystemException> 
    at org.hibernate.id.Assigned.generate(Assigned.java:34) 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101) 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) 
    at com.sun.proxy.$Proxy92.persist(Unknown Source) 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:506) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) 
    at com.sun.proxy.$Proxy96.save(Unknown Source) 
    at com.myapp.core.dao.UsersDAOIT.testSave_NullUsername(UsersDAOIT.java:49) 

我很難找到那裏驗證是自動配置的位置。我確實看到Hibernate-validator作爲一個依賴包含在內,甚至指定爲測試作用域,它在處理事物的db端之前似乎沒有通過驗證來響應實體。

任何想法?

在此先感謝!

編輯1:

每評論婁捕獲異常的根本原因:

org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.tafi.everest.core.entity.Users 
    at org.hibernate.id.Assigned.generate(Assigned.java:34) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101] 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at com.sun.proxy.$Proxy97.persist(Unknown Source) ~[na:na] 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:506) ~[spring-data-jpa-1.10.2.RELEASE.jar:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503) ~[spring-data-commons-1.12.2.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488) ~[spring-data-commons-1.12.2.RELEASE.jar:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460) ~[spring-data-commons-1.12.2.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.12.2.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.10.2.RELEASE.jar:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at com.sun.proxy.$Proxy101.save(Unknown Source) ~[na:na] 
    at com.tafi.everest.core.dao.UsersDAOIT.testSave_NullUsername(UsersDAOIT.java:57) ~[test-classes/:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101] 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12] 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12] 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12] 
    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19) [junit-4.12.jar:4.12] 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:275) [surefire-junit4-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173) [surefire-junit4-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:149) [surefire-junit4-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128) [surefire-junit4-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) [surefire-booter-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) [surefire-booter-2.18.1.jar:2.18.1] 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) [surefire-booter-2.18.1.jar:2.18.1] 

這是不是我們預期,Hibernate驗證應該抓住@NotNull試圖保存不@Id之前。更進一步,有另一個測試經過時,它不應該

@Test(expected = ConstraintViolationException.class) 
    public void testSave_LongUsername() { 
     p.setUsername(RandomStringUtils.randomAlphabetic(51)); 
     usersDAO.save(p); 
    } 

編輯2:

Sample project

+0

檢查此鏈接是否有幫助http://stackoverflow.com/questions/8922631/spring-thrown-jpasystemexception-instead-of-duplicatekeyexception –

+0

你嘗試調用'getRootCause'或'getMostSpecificCause'方法,看看是否有你正在尋找的例外? javadoc http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/JpaSystemException.html –

+0

@MadhusudanaReddySunnapu,這樣做並驗證驗證沒有被解僱。請參閱編輯1. – mosgjig

回答

0

JPA的異常說明了一切:你不使用任何ID生成(@GeneratedValue),因此您必須在致電save()之前手動分配ID。此檢查發生在Bean Validation開始之前。

+0

不確定您是否閱讀了編輯1上的更新,但證明不驗證bean驗證是否被調用。 @Size沒有被強制執行,表明在這個過程中沒有考慮到bean驗證。 – mosgjig

2

在測試中,您需要強制EntityManager刷新,因爲驗證發生在Hibernate PreInsert事件中。

所以

@RunWith(SpringRunner.class) 
@DataJpaTest 
@AutoConfigureTestDatabase(replace=Replace.NONE) 
public class UsersDAOIT { 

    @Autowired 
    private UsersDAO usersDAO; 

    @PersistenceContext 
    private EntityManager entityManager; 

    private static final String USER_NAME = RandomStringUtils.randomAlphabetic(50); 
    private static final String PASSWORD = RandomStringUtils.randomAlphabetic(50); 

    private Users p; 

    @Before 
    public void onStartUp() { 
     p = new Users(); 
     p.setUsername(USER_NAME); 
     p.setPassword(PASSWORD); 
     p.setEnabled(Boolean.TRUE); 
    } 

    @Test(expected = ConstraintViolationException.class) 
    public void testSave_NullUsername() { 
     p.setUsername(SOME_EXTRA_LONG_STRING); 
     usersDAO.save(p); 
     entityManager.flush(); 
    } 
} 

基於這個原因,以及(在PreInsert事件驗證)在@Id領域的@NotNull審定會也從未解僱。生成ID(或在您的情況下必須分配)之前插入,所以他們將被創建/必須在此之前分配。