2016-10-02 114 views
0

隨着SpringJUnit4ClassRunner,JUnit 4中和Spring測試我寫單元測試Service它使用了Spring數據JPA Repository和嵌入式HSQL數據庫:彈簧試驗使用JUnit 4和Spring數據JPA:的NoSuchMethodError org.hibernate.engine.spi.SessionFactoryImplementor.getProperties

@Ignore 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath*:unitTestFullConfig.xml") 
public class InMemoryDBFullTestBaseClass { 
} 

public final class ActorServiceImplTest extends InMemoryDBFullTestBaseClass { 
    @Inject 
    private ActorService service; 

    @Test 
    public final void saveActor() throws Exception { 
     service.save(new ActorDTO(null, "testName", "testSurname", new Date(), Collections.emptyList())); 

     assertEquals(1, service.getAll().size()); 
    } 
} 

我跑測試與required javaagent option on VM,與配置:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:mvc="http://www.springframework.org/schema/mvc" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/data/jpa 
    http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 

     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

    <!-- Configure the data source bean --> 
    <jdbc:embedded-database id="dataSource" type="HSQL"> 
    </jdbc:embedded-database> 
    <!-- Enable annotation driven transaction management --> 
    <tx:annotation-driven/> 
    <mvc:annotation-driven/> 
    <context:component-scan base-package="beans"/> 

    <!-- Create default configuration for Hibernate --> 
    <bean id="hibernateJpaVendorAdapter" 
      class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> 

    <!-- Configure the entity manager factory bean --> 
    <bean id="entityManagerFactory" 
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="dataSource" ref="dataSource"/> 
     <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> 
     <property name="loadTimeWeaver"> 
      <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> 
     </property> 
     <!-- Set JPA properties --> 
     <property name="jpaProperties"> 
      <props> 
       <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> 
       <prop key="javax.persistence.schema-generation.database.action">none</prop> 
       <prop key="hibernate.ejb.use_class_enhancer">true</prop> 
       <prop key="hibernate.hbm2ddl.auto">create</prop> 
       <prop key="hibernate.show_sql">true</prop> 
      </props> 
     </property> 
     <!-- Set base package of your entities --> 
     <property name="packagesToScan" value="models"/> 
     <!-- Set share cache mode --> 
     <property name="sharedCacheMode" value="ENABLE_SELECTIVE"/> 
     <!-- Set validation mode --> 
     <property name="validationMode" value="NONE"/> 
     <property name="persistenceUnitName" value="testJPA" /> 
    </bean> 

    <!-- Configure the transaction manager bean --> 
    <bean id="transactionManager" 
      class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 



    <!-- 
     Configure Spring Data JPA and set the base package of the 
     repository interfaces 
    --> 
    <jpa:repositories base-package="beans.repositories"/> 
</beans> 

但我得到:

Error creating bean with name 'entityManagerFactory' defined in URL [file:/E:/workspace/film-site/out/test/main/unitTestFullConfig.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Properties; at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean...

測試配置和applicationContext.xml(其中工程爲Tomcat應用程序)之間的唯一區別是嵌入在測試中使用的數據庫,但即使我用dataSource從項目:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
    <property name="driverClass" value="org.postgresql.Driver"/> 
    <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/film-site"/> 
    <property name="user" value="postgres"/> 
    <property name="password" value="postgres"/> 
    <property name="maxPoolSize" value="10"/> 
    <property name="maxStatements" value="0"/> 
    <property name="minPoolSize" value="5"/> 
</bean> 

我仍然面臨着同樣的問題(項目正常工作)。另外,我不認爲問題是我沒有hibernate.properties文件,因爲我在這裏詢問了它:Spring Data configuration - hibernate.properties not found。我用Spring 4.3.2.RELEASE,Hibernate Core 5.2.0.Final,Hibernate Entity Manager 5.1.0.Final,Spring Data 1.10.2.RELEASE JPA,Spring Data Commons 1.12.2.RELEASESpring Data Commons Core 1.4.1.RELEASE。如果有人能幫助我,我會很高興 - 事先感謝您。 更新:我改變jpaPropertiesjpaPropertyMapentityManagerFactory

<property name="jpaPropertyMap"> 
     <map> 
      <entry key="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> 
      <entry key="javax.persistence.schema-generation.database.action" value="none" /> 
      <entry key="hibernate.ejb.use_class_enhancer" value="true" /> 
      <entry key="hibernate.hbm2ddl.auto" value="create" /> 
      <entry key="hibernate.show_sql" value="true" /> 
     </map> 
    </property> 

兼評依賴於hibernate-entitymanager,但它仍然無法正常工作。我也有同樣的問題,當我切換到休眠5.1 更新2:我創建一個Java版本的配置,也許這​​將幫助別人看到我犯了一個錯誤:

package config; 

import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 
import org.springframework.orm.jpa.JpaTransactionManager; 
import org.springframework.orm.jpa.JpaVendorAdapter; 
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 

import javax.persistence.EntityManagerFactory; 
import javax.persistence.SharedCacheMode; 
import javax.persistence.ValidationMode; 
import javax.sql.DataSource; 
import java.util.HashMap; 
import java.util.Map; 

@Configuration 
public class HibernateConfig { 
    @Bean 
    public DataSource dataSource() { 
     return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build(); 
    } 

// Create default configuration for Hibernate 
    @Bean 
    public JpaVendorAdapter jpaVendorAdapter() { 
     return new HibernateJpaVendorAdapter(); 
    } 

// Configure the entity manager factory bean 
    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
     LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 

     factory.setDataSource(dataSource()); 
     factory.setJpaVendorAdapter(jpaVendorAdapter()); 
     factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); 
     factory.setJpaPropertyMap(createJpaProperties()); 
     factory.setPackagesToScan("models"); 
     factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE); 
     factory.setValidationMode(ValidationMode.NONE); 
     factory.setPersistenceUnitName("testJPA"); 

     return factory; 
    } 

    @Bean 
    public JpaTransactionManager transactionManager() { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory((EntityManagerFactory) entityManagerFactory()); 
     return transactionManager; 
    } 

    private Map<String, ?> createJpaProperties() { 
     Map<String, Object> propertyMap = new HashMap(); 
     propertyMap.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 
     propertyMap.put("javax.persistence.schema-generation.database.action", "none"); 
     propertyMap.put("hibernate.ejb.use_class_enhancer", true); 
     propertyMap.put("hibernate.hbm2ddl.auto", "create"); 
     propertyMap.put("hibernate.show_sql", true); 

     return propertyMap; 
    } 
} 

UPDATE 2016-10 -04:我創建了Github repository which shows problem,在那裏您會看到該應用程序本身工作得很好(只需在index,jsp文件中添加Actor,但它不適用於測試)。附:我從Intellij IDEA(「運行」按鈕)將war:exploded部署到Tomcat 8.0.24本地實例。

+0

當你說,它運行良好,你用哪個應用服務器環context配置?它在共享庫中是否帶有hibernate? – AntJavaDev

+0

@AntJavaDev我從Intellij IDEA(「運行」按鈕)部署'war:exploded'到Tomcat 8.0.24本地實例,我不確定,但我不認爲Tomcat在共享庫中有Hibernate,我甚至不認爲關於它早些時候:) –

+0

好的,你的github的例子不是那麼有效,但無論如何,我設法在本地運行它與你應用的休眠版本(4.3.11.Final而不是5.你指的是你的帖子)它運行在Tomcat 8和JUnit runner上。我也得到它在hibernate 5.1.0.Final和5.2.0.Final下運行,在答案中提到。 – AntJavaDev

回答

1

我在GitHub上檢查了你的例子,單元測試已經爲我修改了一些代碼。但首先我想說的是,在開始的時候,這對我來說有點像另一個例外。它就像如下:需要改變來解決這個問題就像遵循HibernateConfig

Caused by: java.lang.ClassCastException: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean$$EnhancerBySpringCGLIB$$fedd095f cannot be cast to javax.persistence.EntityManagerFactory 

JpaTransactionManager配置:

@Bean 
public JpaTransactionManager transactionManager(EntityManagerFactory emf) { 
    JpaTransactionManager transactionManager = new JpaTransactionManager(); 
    transactionManager.setEntityManagerFactory(emf); 
    return transactionManager; 
} 

不像在這種情況下EntityManagerFactory原來配置的版本被注入爲Spring管理的bean,而不是使用HibernateConfig.entityManagerFactory()方法創建的獨立實例。

也做了其他更改,但它們與問題主題沒有直接關係。如果你願意,我也可以提供。

+0

您能否提供您的更改?因爲當我在Intellij中將我的代碼作爲新項目打開時,它變得瘋狂(例如,當我嘗試運行測試時,得到'java.lang.ClassNotFoundException:javax.servlet.ServletContext'),並且我認爲它顯示了我的問題的真正原因.. –

+0

經過幾個小時的更改依賴版本,'乾淨安裝'和Intellij重新安裝,它的工作!你說得對,'JpaTransactionManager'配置必須改爲你的。如果你想提供你的改變,我仍然會很高興,也許我可以在我的代碼中添加一些改進。 –

+0

@Pneumokok修改和建議單獨提供[答案](http://stackoverflow.com/questions/39815784/spring-test-with-junit-4-and-spring-data-jpa-nosuchmethoderror-org-hibernate-en/39950463#39950463) –

1

同時固定在Hibernate社區這個bug的SessionFactoryImplementor.getProperties()的簽名5.2改爲返回Map而非Propertiesreference
因此,您應該使用Map

您正在使用休眠5.2.0最終,在新版本5.2.3冬眠最終社區已經鞏固少數的Hibernate EntityManager的問題。 download link。請試用這個版本。

建議:分別

1)使用下面休眠核和休眠-EntityManager的版本而不是5.2.0.Final5.1.0.Final版本。

<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-core</artifactId> 
    <version>5.2.1.Final</version> 
</dependency> 
<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-entitymanager</artifactId> 
    <version>5.2.1.Final</version> 
</dependency> 

2)恢復到休眠的5.1.x版本(我想你應該有這個沒有問題。)
3)如果第一&第二建議沒有再合作移動到Release 6.0.1.GA,它與Hibernate 5.2兼容。 community discussion
4)代替下面配置(只是爲了試驗和誤差方法的緣故)

<!-- Configure the entity manager factory bean --> 
<bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
... 
<!-- Set JPA properties --> 
<property name="jpaPropertyMap"> 
    <map> 
    ... 
    </map> 
</property> 
... 
</bean> 

使用此代碼:

<!-- Configure the entity manager factory bean --> 
<bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
... 
    <property name="jpaPropertyMap" ref="jpaPropertyMap" /> 
... 
</bean> 

<util:map id="jpaPropertyMap" map-class="java.util.TreeMap"> <!-- OR <util:map id="jpaPropertyMap"> OR <util:map id="jpaPropertyMap" map-class="java.util.HashMap">--> 

    <entry key="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> 
    ... 
    <entry key="hibernate.show_sql" value="true"/> 
    ... 
</util:map> 
+0

嗯有趣,並有可能做些什麼呢?我將'jpaProperties'改爲'jPaPropertyMap'(''etc)for'entityManagerFactory',我仍然遇到同樣的問題。 –

+0

其實hibernate 5.2.x是最新版本,可能從現在起他們要我們用Map。所以,而不是使用XML配置嘗試以編程方式配置休眠。在這裏你可以使用不同的地圖,如HashMap。 –

+0

我在我的文章中創建了一個Java配置版本,也許我是一個新手 - 但我仍然不知道應該在哪裏使用'Map' - 'jpaPropertyMap'是一個'Map',我沒有看到另一個地方。 –

3

使用Hibernate核心5.2 休眠EntityManager 5.1很可能會導致此問題。 5.2將EntityManager實現移到核心模塊中,以便最終在類路徑中實現2個JPA實現,這可能會導致Spring框架無法檢測到Hibernate版本以進行引導。

請確保您使用休眠5.1並參考hibernate-entitymanager神器 5.2並且只能拉hiberante-core

+0

謝謝,但即使我在'pom.xml'中評論'entity-manager',錯誤依然會發生。也許@Rohit Gaikwad是對的,但我不知道如何以及在哪裏使用'Map'而不是屬性,我將'jpaProperties'更改爲'jpaPropertyMap',甚至與您的答案相結合,它不起作用。 –

+0

另外,當我切換到休眠5.1時,也遇到同樣的問題。 –

+0

當您切換到5.1時,您是否已從Map恢復到配置中的屬性? –

1

它可能超出了主題,但您的示例項目也可以通過一些額外的更改進行改進,以防止將來出現問題。此改進如下:

  1. 明確定義您正在使用的所有Maven插件的版本和配置。至少它是Maven Compiler Plugin
<plugin> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>3.1</version> 
    <configuration> 
     <source>${java.source}</source> 
     <target>${java.target}</target> 
     <encoding>UTF-8</encoding> 
    </configuration> 
</plugin> 
  • 關注行家項目結構約定。在你的情況test相關的源代碼必須放置在src/test/java文件夾而不是src/main/test
  • my-app 
    |-- pom.xml 
    `-- src 
        |-- main 
        | `-- java 
        |  `-- com 
        |   `-- mycompany 
        |    `-- app 
        |     `-- App.java 
        `-- test 
         `-- java 
          `-- com 
           `-- mycompany 
            `-- app 
             `-- AppTest.java 
    
  • 這是很好的做法,定義自己的包名稱,而不是僅僅beansconfig。例如,它可以是com.pneumokok.mvccom.pneumokok.service,com.pneumokok.testcom.pneumokok.model。它可以幫助你component scan使用base package名稱。

  • 正如你正確地指出有必要添加javax.servlet-api依賴性,但以限定provided範圍是很重要的

  • <dependency> 
         <groupId>javax.servlet</groupId> 
         <artifactId>javax.servlet-api</artifactId> 
         <version>3.1.0</version> 
         <scope>provided</scope> 
    </dependency> 
    
  • 最後但並非最不重要的爲每個應用程序層和環境使用單獨的Spring上下文定義。在您的例子幾個方面定義可用於:
  • 的src /主/資源/ COM/pneumokok /服務/ applicationContext.xml的

    Spring爲服務層

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:tx="http://www.springframework.org/schema/tx" 
         xmlns:context="http://www.springframework.org/schema/context" 
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
    
        <context:component-scan base-package="com.pneumokok.service"/> 
        <!-- Enable annotation driven transaction management --> 
        <tx:annotation-driven/> 
    
        ... 
    
    </beans> 
    

    上下文配置src/main/resources/com/pneumokok/mvc/applicationContext.xml

    Spring context con成形爲MVC層

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:mvc="http://www.springframework.org/schema/mvc" 
         xmlns:context="http://www.springframework.org/schema/context" 
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
    
        <context:component-scan base-package="com.pneumokok.mvc"/> 
        <!-- Enable annotation driven transaction management --> 
        <mvc:annotation-driven/> 
    
        ... 
    
    </beans> 
    

    的src /主/資源/ COM/pneumokok/applicationContext.xml中

    爲Servlet容器環境Spring上下文配置

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:mvc="http://www.springframework.org/schema/mvc" 
         xmlns:context="http://www.springframework.org/schema/context" 
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
    
        <import resource="com/pneumokok/service/applicationContext.xml"/> 
        <import resource="com/pneumokok/mvc/applicationContext.xml"/> 
        <import resource="com/pneumokok/dao/applicationContext.xml"/> 
    
        <bean name="dataSource"> 
        //Servlet container DataSource configuration 
        </bean> 
    
        ... 
    
    </beans> 
    

    的src /主/資源/com/pneumokok/test/applicationContext.xml

    Sp爲測試環境

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:mvc="http://www.springframework.org/schema/mvc" 
         xmlns:context="http://www.springframework.org/schema/context" 
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
    
        <import resource="com/pneumokok/service/applicationContext.xml"/> 
        <import resource="com/pneumokok/mvc/applicationContext.xml"/> 
        <import resource="com/pneumokok/dao/applicationContext.xml"/> 
    
        <bean name="dataSource"> 
        //Test DataSource configuration 
        </bean> 
    
        ... 
    
    </beans>