2011-07-18 129 views
5

我有幾個會寫入單元測試的會話bean。我已經設置Maven在src/main/resources/META-INF目錄中包含一個persistence.xml,該目錄引用了本地MySQL數據庫用於開發目的。我在src/test/resources/META-INF目錄中有另一個persistence.xml,它指向嵌入式Derby數據庫__default。測試部署到嵌入式GlassFish 3.1容器。嵌入式GlassFish忽略Maven測試資源

然而,當我運行測試,我得到以下錯誤:

java.lang.RuntimeException: javax.naming.NamingException: Lookup failed for 'jdbc/mylog' 

JDBC/mylog的是,在主目錄中的持久性單元是指MySQL數據庫。顯然,它忽略了測試目錄中的持久性單元,但我不知道爲什麼。

Maven根據我可以判斷的正確設置類路徑,在類之前使用測試類,並在實際目標/測試類/ META-INF目錄中窺探它複製了正確的嵌入式Derby,持久性單元。

[DEBUG] Test Classpath : 
[DEBUG] C:\Users\Laurens\Documents\Projects\Mylog\target\test-classes 
[DEBUG] C:\Users\Laurens\Documents\Projects\Mylog\target\classes 
[DEBUG] C:\Users\Laurens\.m2\repository\org\eclipse\persistence\eclipselink\2.2.0\eclipselink-2.2.0.jar 
[DEBUG] C:\Users\Laurens\.m2\repository\org\eclipse\persistence\javax.persistence\2.0.3\javax.persistence-2.0.3.jar 
[DEBUG] C:\Users\Laurens\.m2\repository\org\eclipse\persistence\org.eclipse.persistence.jpa.modelgen.processor\2.2.0\org.eclipse.persistence.jpa.modelgen.processor-2.2.0.jar 
[DEBUG] C:\Users\Laurens\.m2\repository\org\glassfish\extras\glassfish-embedded-all\3.1\glassfish-embedded-all-3.1.jar 
[DEBUG] C:\Users\Laurens\.m2\repository\javax\javaee-web-api\6.0\javaee-web-api-6.0.jar 
[DEBUG] C:\Users\Laurens\.m2\repository\junit\junit\4.8.1\junit-4.8.1.jar 

有關如何讓GlassFish使用適當的持久性單元的任何提示非常感謝!謝謝!

+0

我在不同的arquitecture條件下有類似的問題,骯髒的解決方案是合併成一個persistence.xml這兩個persistente單位,生產和測試。 –

回答

11

使用嵌入式Glassfish運行測試時,在執行maven-surefire插件目標(用於運行測試階段)之前,JPA提供程序不使用命令行上顯示的類路徑。嵌入式Glassfish部署可作爲測試範圍一部分的工件,如ScatteredArchive。除非嵌入的Glassfish配置指定了Glassfish安裝根目錄和Glassfish域的位置,否則通常會在名稱爲gfembed<a_random_number>tmpjava.io.tmpdir目錄中創建這種分散的存檔。

當嵌入式Glassfish的域與部署散射歸檔製備,要部署的文件通常被複制到容納所有應用程序所需的類(包括所有的依賴關係)的分解目錄。該目錄通常恰好存在於GF_EMBED_DOMAIN_HOME/applications/<application_name>目錄中。您的src/main/resources/META-INFsrc/test/resources/META-INF目錄中的persistence.xml文件在此處被複制到<application-name>/META-INF目錄中。不用說,最後被複制的那個,或者沒有被覆蓋的那個是JPA提供程序在測試期間使用的那個。這總是碰巧是src/main/resources/META-INF中的文件。

可以克服這種情況,有兩種方式:

1.使用自定義的Glassfish域配置文件

你可以指定一個域配置文件(domain.xml)將包含數據源定義爲jdbc/mylog 。這是我目前所做的,因爲它非常靈活,並且域配置文件也可以包含其他配置。該配置文件,需要指定爲通過以下方式測試裝置的一部分:

Map<String, Object> props = new HashMap<String, Object>(); 
props.put("org.glassfish.ejb.embedded.glassfish.installation.root", "./glassfish-install/glassfish"); 
container = EJBContainer.createEJBContainer(props); 
context = container.getContext(); 
datasource = (DataSource) context.lookup("jdbc/mylog"); //You can lookup the datasource too, to confirm that your setup is successful. 

前面提到的glassfish-install目錄及其子目錄glassfish存在於Maven項目根(也簽入到版本控制); glassfish目錄必須包含domain1/config的目錄結構,以表示名稱爲domain1的Glassfish域的目錄結構。該項目中的結構可以在下面的截圖中看到。其他相關文件(JDBC資源適配器JAR等)可以從Glassfish安裝目錄中獲得,但是如果配置正確,這些文件通常也可以通過嵌入的Glassfish運行時放置在正確的位置。

Glassfish domain configuration file location

Glassfish的域配置文件的內容是從默認的嵌入式Glassfish的使用不同,除了數據源和連接池配置(在我的用例中添加相關項,我進行集成測試,已經貼在下面):

<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0"> 
    <system-applications/> 
    <applications/> 
    <resources> 
    <jdbc-resource pool-name="MyPool" jndi-name="jdbc/mylog"/> 
    ... 
    <jdbc-connection-pool driver-classname="" datasource-classname="org.apache.derby.jdbc.ClientDataSource" res-type="javax.sql.DataSource" description="" name="MyPool" ping="true"> 
     <property name="User" value="APP"></property> 
     <property name="RetrieveMessageText" value="true"></property> 
     <property name="CreateDatabase" value="true"></property> 
     <property name="ServerName" value="localhost"></property> 
     <property name="Ssl" value="off"></property> 
     <property name="SecurityMechanism" value="4"></property> 
     <property name="TraceFileAppend" value="false"></property> 
     <property name="TraceLevel" value="-1"></property> 
     <property name="PortNumber" value="1527"></property> 
     <property name="LoginTimeout" value="0"></property> 
     <property name="Password" value="APP"></property> 
     <property name="databaseName" value="MYDB"></property> 
    </jdbc-connection-pool> 
    ... 
    </resources> 
    <servers> 
    <server name="server" config-ref="server-config"> 
     <resource-ref ref="jdbc/__TimerPool"/> 
     <resource-ref ref="jdbc/__default"/> 
     <resource-ref ref="jdbc/mylog"/> 
    </server> 
    </servers> 
    ... 
... 

default domain.xml file can be downloaded from the java.net site和修改,你想保留的變化儘可能小,而不是複製一個從GlassFish安裝的事件。

2.複製過的persistence.xml文件

可以添加目標,Maven的POM文件,備份和persistence.xml文件複製從src/test/resources/META-INFsrc/main/resources/META-INF,在test階段之前。測試階段完成後,原件被恢復。我不會詳細討論這個問題,因爲在a related StackOverflow question中已經討論過類似的解決方案。我沒有使用這種方法進行集成測試,因爲我需要對persistence.xml進行修改,比如創建自定義領域。然而,我將它用於單元測試,因爲JPA提供程序將從target/classes而不是target/test-classes獲取persistence.xml文件,儘管後者首先出現在類路徑順序中。如果您使用Hibernate作爲您的JPA提供程序,則爲org.hibernate.ejb記錄器啓用TRACE日誌記錄(因爲Ejb3Configuration類負責執行查找)將使您確信test-classes中的文件不會被拾取。


注:

大多數的回答假設Glassfish的3.1,但可以把握好爲即將來臨的版本。

+0

哇,這是驚人的詳細Vineet!我選擇了最靈活的方式,現在它的工作完美無瑕。太感謝了! – Laurens

+0

@勞倫斯,好吧,很高興知道它有幫助。 –

+0

偉大的答案,Vineet。嵌入式Glassfish在升級到3.1.2後停止工作,但在做完這些解釋之後,我設法讓它恢復正常工作。謝謝! – Vetle

0

通過「嵌入的GlassFish容器」,你的意思是你運行的GlassFish Maven插件? Maven插件的類路徑與Maven測試類路徑的不同和管理方式不同。您可能需要使用不同的類路徑。

+0

嗨瑞安,感謝您的快速響應!我沒有使用插件。我在我的POM中將glassfish-embedded-all-3.1作爲測試範圍的依賴項。 – Laurens

+0

@Laurens:那麼你的測試類是在運行測試的同一個JVM中啓動glassfish的?我對GF不熟悉,但是你所描述的聽起來不對。你能提供一個小的,可執行的問題的例子嗎? –

+0

是的。我的印象是,這是使用嵌入式GlassFish進行單元測試的重點,因此您不需要完全安裝構建服務器。我設法使用Vineets的建議來解決問題。非常感謝! – Laurens

0

這個答案可能聽起來很愚蠢,但我一直在尋找一種方法,讓我通過Run As - >JUnit Test從eclipse運行這些測試。這是我做到的:

@BeforeClass 
public static void setUp() throws IOException { 
    Files.copy(new File("target/test-classes/META-INF/persistence.xml"), new File("target/classes/META-INF/persistence.xml")); 
    // ... 
} 

我只是將test/persistence.xml複製到classes/persistence.xml。這工作。