領先一步
VMware 提供培訓和認證,以加速您的進步。
瞭解更多我很高興宣佈 SpringSource 的 OSGi 測試樁 1.0.0.M1 版本釋出。這些樁提供了一種在不需要完整的 OSGi 容器的情況下,對複雜的 OSGi Framework 互動進行單元測試的方法。
@Test
public void startAndStop() throws Exception {
BundleActivator bundleActivator = new DumpBundleActivator();
BundleContext context = createMock(BundleContext.class);
Filter filter = createMock(Filter.class);
String filterString = "(objectClass=" + DumpContributor.class.getName() + ")";
expect(context.createFilter(filterString)).andReturn(filter);
context.addServiceListener((ServiceListener)anyObject(), eq(filterString));
expect(context.getServiceReferences(DumpContributor.class.getName(), null)).andReturn(new ServiceReference[0]).atLeastOnce();
ServiceRegistration generatorRegistration = createMock(ServiceRegistration.class);
ServiceRegistration summaryRegistration = createMock(ServiceRegistration.class);
ServiceRegistration jmxRegistration = createMock(ServiceRegistration.class);
ServiceRegistration threadRegistration = createMock(ServiceRegistration.class);
ServiceRegistration heapRegistration = createMock(ServiceRegistration.class);
expect(context.registerService(eq(DumpGenerator.class.getName()), isA(StandardDumpGenerator.class), (Dictionary<?,?>)isNull())).andReturn(generatorRegistration);
expect(context.registerService(eq(DumpContributor.class.getName()), isA(SummaryDumpContributor.class), (Dictionary<?,?>)isNull())).andReturn(summaryRegistration);
expect(context.registerService(eq(DumpContributor.class.getName()), isA(JmxDumpContributor.class), (Dictionary<?,?>)isNull())).andReturn(jmxRegistration);
expect(context.registerService(eq(DumpContributor.class.getName()), isA(ThreadDumpContributor.class), (Dictionary<?,?>)isNull())).andReturn(threadRegistration);
expect(context.registerService(eq(DumpContributor.class.getName()), isA(HeapDumpContributor.class), (Dictionary<?,?>)isNull())).andReturn(heapRegistration);
generatorRegistration.unregister();
summaryRegistration.unregister();
jmxRegistration.unregister();
threadRegistration.unregister();
heapRegistration.unregister();
context.removeServiceListener((ServiceListener)anyObject());
replay(context, filter, generatorRegistration, summaryRegistration, jmxRegistration, threadRegistration, heapRegistration);
bundleActivator.start(context);
bundleActivator.stop(context);
verify(context, filter, generatorRegistration, summaryRegistration, jmxRegistration, threadRegistration, heapRegistration);
}
建立一套測試樁是一項微妙的平衡,尤其是在涉及像 OSGi Framework 這樣複雜的 API 時。 一方面,您需要實現足夠簡單,不太可能引入錯誤,並且您可以允許使用者指定呼叫的行為和返回值。 另一方面,您需要足夠複雜的實現,以便複雜物件(例如ServiceTracker)在呼叫樁時可以獲得預期的行為。
考慮到所有這些,我開始為BundleContext, Bundle, ServiceReference和ServiceRegistration實現測試樁。 為了瞭解這些測試樁所產生的差異,以下是將之前的測試轉換為使用樁後的結果。
@Test
public void startAndStop() throws Exception {
BundleActivator bundleActivator = new DumpBundleActivator();
StubBundleContext bundleContext = new StubBundleContext().addFilter(new ObjectClassFilter(DumpContributor.class));
bundleActivator.start(bundleContext);
assertServiceListenerCount(bundleContext, 1);
assertServiceRegistrationCount(bundleContext, DumpGenerator.class, 1);
assertServiceRegistrationCount(bundleContext, DumpContributor.class, 4);
bundleActivator.stop(bundleContext);
assertCleanState(bundleContext);
}
正如你所看到的,這個測試現在更容易閱讀和維護,但最重要的是它更容易理解。 這個測試的基本構建塊是StubBundleContext。 此上下文被傳遞到DumpBundleActivator的啟動呼叫,其中註冊了服務。 但真正有趣的是斷言。
使用StubBundleContext,使用者可以斷言他們測試所需的一切。 然而,測試樁包還包括一個OSGiAssert類,使典型的斷言更具可讀性。 在這種情況下,您可以看到在呼叫start之後,我們希望註冊一個ServiceListener,註冊一個DumpGenerator服務,並註冊四個DumpContributor服務。 呼叫stop後,我們要確保一切都已清理完畢,並且系統處於乾淨狀態。