2011-08-23 36 views
11

Tôi đang cố gắng tìm ra cách triển khai thử nghiệm tích hợp nhiều gói trong OSGi bằng cách sử dụng JUnit.Sử dụng các dịch vụ khai báo OSGi trong ngữ cảnh của một thử nghiệm JUnit

Với thử nghiệm tích hợp, tôi có nghĩa là tạo một tập hợp con các gói để tự động xác thực chức năng trong hệ thống con đó.

Chúng tôi đang chạy Equinox và sử dụng Eclipse làm toolchain. Eclipse cung cấp tùy chọn "Run as JUnit Plug-in" mang khung OSGi lên và khởi tạo các gói cấu hình, vì vậy tôi đoán đây là đường dẫn để làm theo, nhưng tôi không tìm cách chèn các tham chiếu DS vào các thử nghiệm của mình. Tôi đã nhìn thấy việc sử dụng ServiceTracker như một phương tiện có lập trình để truy cập vào các gói dịch vụ khác nhau, nhưng điều đó đánh bại mục đích của việc có DS, phải không?

Tôi chỉ mới bắt đầu với OSGI, vì vậy tôi nghĩ tôi chỉ thiếu một số câu đố có thể cho phép tôi đưa các bài kiểm tra nhiều bó của mình lại với nhau.

Bất kỳ ý tưởng nào?

Cảm ơn, Gerard.

* EDIT: GIẢI PHÁP *

Sau khi nhìn sâu hơn vào vấn đề này, cuối cùng tôi đã tìm ra cách để đặt này thử nghiệm hội nhập mult-bó tại chỗ bằng cách sử dụng plug-in JUnit tính năng:

Đối các dịch vụ động tiêm để làm việc, người ta phải tạo ra một tập tin định nghĩa dịch vụ, nơi phụ thuộc tiêm phải được khai báo, vì nó thường được thực hiện khi làm việc với DS. Tệp này đi (thường) trong thư mục OSGI-INF/. ví dụ. OSGI-INF/service.xml

service.xml phải khai báo phụ thuộc yêu cầu cho thử nghiệm này, nhưng không cung cấp một dịch vụ của riêng nó:

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> 

này sẽ hướng dẫn DS để tiêm phụ thuộc vào FooService sử dụng phương pháp kê khai onServiceUp. onServiceDown phải được thực hiện khi nó được gọi trong giai đoạn shutdown OSGi sau khi chạy thử nghiệm.

com.test.functionaltest.MyTester chứa các phương pháp thử nghiệm được thực hiện, theo các thực tiễn JUnit điển hình.

Đến đây, tất cả đều là 'theo sách'. Tuy nhiên, nếu Junit được chạy, nó sẽ ném NullPointerException khi truy cập một tham chiếu đến FooService. Lý do cho điều đó là khung công tác OSGi đang trong tình trạng chạy đua với bối cảnh Á hậu thử nghiệm JUnit, và thường, người chạy thử nghiệm Junit thắng cuộc đua đó, thực hiện các kiểm tra trước khi tham chiếu đến dịch vụ được yêu cầu được tiêm.

Để giải quyết tình huống này, bắt buộc phải thực hiện kiểm tra Junit để đợi thời gian chạy OSGi thực hiện công việc của mình. Tôi đã giải quyết vấn đề này bằng cách sử dụng một CountDownLatch, được khởi tạo cho số lượng các dịch vụ phụ thuộc được yêu cầu trong thử nghiệm. Sau đó, mỗi phương pháp tiêm phụ thuộc đếm ngược và khi chúng được thực hiện xong, thử nghiệm sẽ bắt đầu. Mã này trông như thế này:

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(); 
} 

Lưu ý rằng fooService tài liệu tham khảo cần phải được tĩnh để cho phép chia sẻ các tài liệu tham khảo phục vụ giữa OSGi và bối cảnh thực hiện JUnit. CountDownLatch cung cấp cơ chế đồng bộ hóa cấp cao để xuất bản an toàn tài liệu tham khảo được chia sẻ này.

Sau đó, kiểm tra sự phụ thuộc nên được bổ sung trước khi thực hiện kiểm tra:

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

Bằng cách này, khuôn khổ Junit đợi cho dịch vụ OSGi DS để tiêm phụ thuộc hay thất bại sau khi thời gian chờ.

Tôi mất khá nhiều thời gian để hoàn toàn tìm ra điều này. Tôi hy vọng nó sẽ tiết kiệm một số nhức đầu cho các lập trình viên trong tương lai.

Trả lời

6

* EDIT: GIẢI PHÁP *

Sau khi nhìn sâu hơn vào vấn đề này, cuối cùng tôi đã tìm ra cách để đặt này thử nghiệm hội nhập mult-bó tại chỗ bằng cách sử dụng plug-in JUnit tính năng:

Đối các dịch vụ động tiêm để làm việc, người ta phải tạo ra một tập tin định nghĩa dịch vụ, nơi phụ thuộc tiêm phải được khai báo, vì nó thường được thực hiện khi làm việc với DS. Tệp này đi (thường) trong thư mục OSGI-INF/. ví dụ. OSGI-INF/service.xml

service.xml phải khai báo phụ thuộc yêu cầu cho thử nghiệm này, nhưng không cung cấp một dịch vụ của riêng nó:

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> 

này sẽ hướng dẫn DS để tiêm phụ thuộc vào FooService sử dụng phương pháp kê khai onServiceUp. onServiceDown phải được thực hiện khi nó được gọi trong giai đoạn shutdown OSGi sau khi chạy thử nghiệm.

com.test.functionaltest.MyTester chứa các phương pháp thử nghiệm được thực hiện, theo các thực tiễn JUnit điển hình.

Đến đây, tất cả đều là 'theo sách'. Tuy nhiên, nếu Junit được chạy, nó sẽ ném NullPointerException khi truy cập một tham chiếu đến FooService.Lý do cho điều đó là khung công tác OSGi đang trong tình trạng chạy đua với bối cảnh Á hậu thử nghiệm JUnit, và thường, người chạy thử nghiệm Junit thắng cuộc đua đó, thực hiện các kiểm tra trước khi tham chiếu đến dịch vụ được yêu cầu được tiêm.

Để giải quyết tình huống này, bắt buộc phải thực hiện kiểm tra Junit để đợi thời gian chạy OSGi thực hiện công việc của mình. Tôi đã giải quyết vấn đề này bằng cách sử dụng một CountDownLatch, được khởi tạo cho số lượng các dịch vụ phụ thuộc được yêu cầu trong thử nghiệm. Sau đó, mỗi phương pháp tiêm phụ thuộc đếm ngược và khi chúng được thực hiện xong, thử nghiệm sẽ bắt đầu. Mã này trông như thế này:

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(); 
} 

Lưu ý rằng fooService tài liệu tham khảo cần phải được tĩnh để cho phép chia sẻ các tài liệu tham khảo phục vụ giữa OSGi và bối cảnh thực hiện JUnit. CountDownLatch cung cấp cơ chế đồng bộ hóa cấp cao để xuất bản an toàn tài liệu tham khảo được chia sẻ này.

Sau đó, kiểm tra sự phụ thuộc nên được bổ sung trước khi thực hiện kiểm tra:

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

Bằng cách này, khuôn khổ Junit đợi cho dịch vụ OSGi DS để tiêm phụ thuộc hay thất bại sau khi thời gian chờ.

Tôi mất khá nhiều thời gian để hoàn toàn tìm ra điều này. Tôi hy vọng nó sẽ tiết kiệm một số nhức đầu cho các lập trình viên trong tương lai.

1

Tôi không quen thuộc với các công cụ Eclipse mà bạn đề cập đến, nhưng chúng tôi đã sử dụng thành công Pax Exam để thử nghiệm tích hợp trong Apache Sling. Nếu bạn đã quen với Maven, POM tại https://svn.apache.org/repos/asf/sling/trunk/installer/it/pom.xml có thể giúp bạn bắt đầu và https://github.com/tonit/Learn-PaxExam cũng giống như một điểm khởi đầu tốt.

Sling testing tools cũng có thể trợ giúp trong ngữ cảnh này bằng cách cho phép các gói đóng góp các bài kiểm tra JUnit vào khung OSGi khi chạy, rất hữu ích nếu dự án của bạn tạo ra một bình có thể chạy được.

1

Bạn thiết lập nó bằng cách sử dụng các tab trên cấu hình chạy. Vì vậy, nhấp chuột phải, chọn "chạy dưới dạng", chọn "chạy cấu hình ...", nhấp đúp vào "Kiểm tra trình cắm thêm JUnit", sau đó thêm phụ thuộc của bạn trên tab plugin - khá giống với trình khởi chạy bình thường

một số liên kết: 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

Chắc chắn, đó là tùy chọn "chạy dưới dạng plugin JUnit" mà tôi đã đề cập, nhưng dường như không đủ để nhận được Dịch vụ khai báo. tức là bạn khai báo phương pháp ràng buộc ở đâu? Ngoài ra còn có câu hỏi về ngữ cảnh. Liệu việc tiêm sẽ xảy ra trên bối cảnh Junit? Nếu vậy, cơ chế đó hoạt động như thế nào? – maasg

+0

Giống như bạn sử dụng DS trong ứng dụng. Bạn sẽ cần thêm gói DS, thao tác này quét các gói khác khi chúng được tải và quản lý hệ thống dây điện. Các ràng buộc DS được khai báo trong thành phần xml trong OSGI-INF trong jar của gói. Xem http://www.vogella.de/articles/OSGi/article.html#declarativeservices_run để có giải thích về cách sử dụng DS trong các dự án Trình cắm thêm của Eclipse. HTH – earcam

+0

Cảm ơn bạn đã đề xuất. Các phương pháp tiêm DS không được gọi trong bối cảnh chạy plugin Junit. OSG-INF của tôi khai báo chính xác chúng. – maasg

1

tôi đoán nó sẽ là một chút bụi để có được giữ của org.apache.felix.scr.ScrService và tích cực chờ đợi các thành phần để trở thành ACTIVE. Giao diện này được thực hiện bởi cả equinox và felix.

Java docAPI Usage.

-2

Tôi nghĩ rằng trong giải pháp trên, CountDownLatch không cần thiết.

Vấn đề là JUnit trong DS Context tạo ra một lớp JUnitTest cho riêng mình. Kịch bản DS đầu tiên khởi tạo lớp JUnitTest của bạn và gọi ràng buộc onFooServiceUp cho FooService, nhưng sau khi JUnit này khởi tạo lớp JUnitTest của riêng mình mà không cần gọi phương thức ràng buộc onFooServiceUp. Trong trường hợp này FooService nằm trong JUnitTest không có sẵn.

Nếu bạn khai báo FooService là tĩnh (như bạn đã làm) và gán vào phương thức onFooServiceUp bạn không cần xây dựng với CountDownLatch.

Các vấn đề liên quan