2011-08-23 50 views
11

我想弄清楚如何在OSGi中使用JUnit實現多束集成測試。在JUnit測試環境中使用OSGi聲明式服務

有了集成測試,我的意思是實例化bundle的子集以自動驗證該子系統中的功能。

我們運行Equinox並使用Eclipse作爲工具鏈。 Eclipse提供了「Run as JUnit Plug-in」選項,它將OSGi框架引入並實例化了配置包,所以我想這是要遵循的路徑,但我沒有找到一種方法將DS引用注入到我的測試中。 我已經看到使用ServiceTracker作爲訪問不同服務包的程序化手段,但是這打敗了DS的目的,不是嗎?

我剛剛開始使用OSGI,所以我想我只是錯過了一些讓我將多捆綁測試放在一起的難題。

任何想法?

謝謝,傑拉德。

*編輯:解*

進一步尋找到這個問題後,我終於想通了如何使用JUnit插件功能,把這個MULT束集成測試到位:

對於要動態服務注入工作,必須創建一個服務定義文件,其中必須聲明注入的依賴關係,因爲它通常在使用DS時完成。 此文件通常位於OSGI-INF/目錄下。例如OSGI-INF/service.xml

service.xml中,必須聲明所需的依賴關係爲這個測試,但不提供自己的服務:

service.xml 
<?xml version="1.0" encoding="UTF-8"?> 
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown"> 

    <implementation class="com.test.functionaltest.MyTester"/> 
    <reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/> 

</scr:component> 

這將指示DS使用聲明的onServiceUp方法注入上FooService接口的依賴。 onServiceDown必須在測試運行後的OSGi關閉階段調用時調用。

com.test.functionaltest.MyTester包含要執行的測試方法,遵循典型的JUnit實踐。

到這裏,這一切都是'靠書'。但是,如果運行Junit,則在訪問對FooService的引用時將拋出NullPointerException。原因在於OSGi框架與JUnit測試運行環境處於競爭狀態,並且通常,Junit測試運行器贏得該比賽,在引入所需服務之前執行測試。

爲了解決這種情況,需要使Junit測試等待OSGi運行時執行其工作。我通過使用CountDownLatch解決了這個問題,它初始化爲測試中所需的相關服務的數量。 然後每個依賴注入方法都會倒計時,當它們全部完成時,測試將開始。代碼如下所示:

private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required  
static FooService fooService = null; 
public void onFooServiceUp(FooService service) { 
    fooService = service; 
    dependencyLatch.countDown(); 
} 

注意,fooService參考必須是靜態的,允許共享的OSGi和JUnit執行上下文之間的服務引用。 CountDownLatch提供了一個高級別的同步機制來安全發佈這個共享引用。

然後,依賴檢查應在測試執行前加入:

@Before 
public void dependencyCheck() { 
    // Wait for OSGi dependencies 
    try { 
     dependencyLatch.await(10, TimeUnit.SECONDS); 
     // Dependencies fulfilled 
    } catch (InterruptedException ex) { 
     fail("OSGi dependencies unfulfilled"); 
    } 
} 

這樣對OSGi的DS服務注入依賴JUnit框架等待或超時後失敗。

我花了相當一段時間才完全弄清楚了這一點。我希望將來可以爲同行程序員節省一些頭痛的問題。

回答

6

*編輯:解*

進一步尋找到這個問題後,我終於想通了如何使用JUnit插件功能,把這個MULT束集成測試到位:

對於要動態服務注入工作,必須創建一個服務定義文件,其中必須聲明注入的依賴關係,因爲它通常在使用DS時完成。 此文件通常位於OSGI-INF/目錄下。例如OSGI-INF/service.xml

service.xml中,必須聲明所需的依賴關係爲這個測試,但不提供自己的服務:

service.xml 
<?xml version="1.0" encoding="UTF-8"?> 
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown"> 

    <implementation class="com.test.functionaltest.MyTester"/> 
    <reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/> 

</scr:component> 

這將指示DS使用聲明的onServiceUp方法注入上FooService接口的依賴。 onServiceDown必須在測試運行後的OSGi關閉階段調用時調用。

com.test.functionaltest.MyTester包含要執行的測試方法,遵循典型的JUnit實踐。

到這裏,這一切都是'靠書'。但是,如果運行Junit,則在訪問對FooService的引用時將拋出NullPointerException。原因在於OSGi框架與JUnit測試運行環境處於競爭狀態,並且通常,Junit測試運行器贏得該比賽,在引入所需服務之前執行測試。

爲了解決這種情況,需要使Junit測試等待OSGi運行時執行其工作。我通過使用CountDownLatch解決了這個問題,它初始化爲測試中所需的相關服務的數量。 然後每個依賴注入方法都會倒計時,當它們全部完成時,測試將開始。代碼如下所示:

private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required  
static FooService fooService = null; 
public void onFooServiceUp(FooService service) { 
    fooService = service; 
    dependencyLatch.countDown(); 
} 

注意,fooService參考必須是靜態的,允許共享的OSGi和JUnit執行上下文之間的服務引用。 CountDownLatch提供了一個高級別的同步機制來安全發佈這個共享引用。

然後,依賴檢查應在測試執行前加入:

@Before 
public void dependencyCheck() { 
    // Wait for OSGi dependencies 
    try { 
     dependencyLatch.await(10, TimeUnit.SECONDS); 
     // Dependencies fulfilled 
    } catch (InterruptedException ex) { 
     fail("OSGi dependencies unfulfilled"); 
    } 
} 

這樣對OSGi的DS服務注入依賴JUnit框架等待或超時後失敗。

我花了相當一段時間才完全弄清楚了這一點。我希望將來可以爲同行程序員節省一些頭痛的問題。

1

我不熟悉你提到的Eclipse工具,但我們已經成功使用Pax Exam進行集成測試Apache Sling。如果您熟悉Maven,那麼https://svn.apache.org/repos/asf/sling/trunk/installer/it/pom.xml上的POM可能會幫助您入門,並且https://github.com/tonit/Learn-PaxExam看起來也是一個很好的起點。

Sling testing tools也可以通過允許bundle在運行時向OSGi框架提供JUnit測試來幫助實現此目的,如果您的項目生成可用於測試的可運行JAR文件,這非常有用。

1

使用運行配置中的選項卡進行設置。所以右擊,選擇「運行方式」,選擇「運行配置...」,雙擊「JUnit插件測試」,然後在插件選項卡上添加依賴關係 - 幾乎與普通啓動器相同

一些鏈接: http://publib.boulder.ibm.com/infocenter/ratdevz/v8r0/index.jsp?topic=/org.eclipse.pde.doc.user/guide/tools/launchers/junit_launcher.htmhttp://publib.boulder.ibm.com/infocenter/ratdevz/v8r0/index.jsp?topic=/org.eclipse.pde.doc.user/guide/tools/launchers/junit_main.htm

+0

當然,這是我提到的「作爲JUnit插件運行」選項,但它似乎不足以讓注入聲明服務。即您在哪裏聲明綁定方法?還有關於上下文的問題。注入是否會在Junit環境中發生?如果是這樣,該機制如何運作? – maasg

+0

與您在應用程序中使用DS相同。您需要添加DS捆綁軟件,這會在加載其他捆綁軟件時掃描其他軟件包並管理佈線。 DS綁定在bundle的jar中的OSGI-INF的組件xml中聲明。有關在Eclipse插件項目中使用DS的解釋,請參閱http://www.vogella.de/articles/OSGi/article.html#declarativeservices_run。 HTH – earcam

+0

感謝您的建議。在Junit插件運行的上下文中,DS注入方法沒有被調用。我的OSG-INF正確地聲明它們。 – maasg

1

我想這將是一個有點清潔,以獲得org.apache.felix.scr.ScrService的保持積極等待組件變得活躍。該接口由equinox和felix實現。

Java docAPI Usage

-2

我認爲在上面的解決方案中,CountDownLatch是沒有必要的。

問題是DS Context中的JUnit爲他自己實例化了一個JUnitTest類。第一個DS Context實例化您的JUnitTest類併爲FooService調用綁定onFooServiceUp,但在此之後,JUnit實例化自己的JUnitTest類而不調用onFooServiceUp的綁定方法。在這種情況下,FooService在JUnitTest中不可用。

如果您將FooService聲明爲static(如您所做的那樣)並在方法onFooServiceUp中分配,則不需要使用CountDownLatch進行構造。