簡體   English   中英

在JUnit測試的上下文中使用OSGi聲明性服務

[英]Using OSGi declarative services in the context of a JUnit test

我正在試圖弄清楚如何使用JUnit在OSGi中實現多束集成測試。

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

我們正在運行Equinox並使用Eclipse作為工具鏈。 Eclipse提供了“Run as JUnit Plug-in”選項,它可以啟動OSGi框架並實例化配置包,所以我想這是要遵循的路徑,但我找不到將DS引用注入我的測試的方法。 我已經看到使用ServiceTracker作為一種程序化方法來訪問不同的服務包,但這比使用DS的目的要好,不是嗎?

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

有任何想法嗎?

謝謝,傑拉德。

*編輯:解決方案*

在深入研究這個問題之后,我終於想出了如何使用JUnit插件功能來實現這種多包集成測試:

要使動態服務注入工作,必須創建一個服務定義文件,其中必須聲明注入的依賴項,因為它通常在使用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");
    }
}

這樣,Junit框架等待OSGi DS服務注入依賴項或在超時后失敗。

我花了很長時間才完全弄明白這一點。 我希望將來可以為其他程序員帶來一些麻煩。

*編輯:解決方案*

在深入研究這個問題之后,我終於想出了如何使用JUnit插件功能來實現這種多包集成測試:

要使動態服務注入工作,必須創建一個服務定義文件,其中必須聲明注入的依賴項,因為它通常在使用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");
    }
}

這樣,Junit框架等待OSGi DS服務注入依賴項或在超時后失敗。

我花了很長時間才完全弄明白這一點。 我希望將來可以為其他程序員帶來一些麻煩。

我不熟悉您提到的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測試工具也可以通過允許bundle在運行時向OSGi框架提供JUnit測試來幫助在這種情況下,如果您的項目生成可用於測試的可運行jar,這將非常有用。

您可以使用運行配置上的選項卡進行設置。

所以右鍵單擊,選擇“run as”,選擇“run configurations ...”,雙擊“JUnit Plug-in Test”,然后在插件選項卡上添加依賴項 - 與普通啟動器幾乎相同

一些鏈接: 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

我想抓住org.apache.felix.scr.ScrService並主動等待組件變為ACTIVE會更加清晰。 此接口由equinox和felix實現。

Java docAPI用法

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

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

如果您將FooService聲明為靜態(如您所做)並在方法onFooServiceUp中賦值,則不需要使用CountDownLatch進行構造。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM