Sto cercando di capire come implementare il test di integrazione multi-bundle in OSGi usando JUnit.Utilizzo di servizi dichiarativi OSGi nel contesto di un test JUnit
Con test di integrazione, intendo istanziare un sottoinsieme dei pacchetti per convalidare automaticamente la funzionalità in tale sottosistema.
Stiamo eseguendo Equinox e utilizzando Eclipse come toolchain. Eclipse offre l'opzione "Esegui come plug-in JUnit" che porta in su il framework OSGi e crea un'istanza dei bundle di configurazione, quindi suppongo che questo sia il percorso da seguire, ma non trovo il modo di inserire riferimenti DS nei miei test. Ho visto l'uso di ServiceTracker come un mezzo programmatico per accedere ai diversi pacchetti di servizi, ma che batte lo scopo di avere DS, non è vero?
Sono appena iniziato con OSGI, quindi immagino che mi manchi solo un pezzo del puzzle che mi permetterebbe di mettere insieme i miei test multi-bundle.
Qualche idea?
Grazie, Gerard.
* EDIT: SOLUZIONE *
Dopo aver guardato ulteriormente in questo problema, ho finalmente capito come mettere questo mult-fascio test di integrazione in atto utilizzando il JUnit plug-in funzione:
Per l'iniezione di servizi dinamici per funzionare, occorre creare un file di definizione del servizio in cui devono essere dichiarate le dipendenze iniettate, come di solito si fa quando si lavora con DS. Questo file va (in genere) nella directory OSGI-INF/
. per esempio. OSGI-INF/service.xml
service.xml deve dichiarare le dipendenze richieste per questo test, ma non offrire un servizio a sé stante:
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>
Questo indicherà DS di iniettare la dipendenza FooService utilizzando il metodo dichiarato onServiceUp. onServiceDown deve essere implementato come viene chiamato durante la fase di spegnimento di OSGi dopo l'esecuzione dei test.
com.test.functionaltest.MyTester contiene i metodi di prova da eseguire, seguendo le pratiche tipiche di JUnit.
Fino a qui, è tutto 'dal libro'. Tuttavia, se viene eseguito Junit, genererà NullPointerException quando accede a un riferimento a FooService. La ragione è che il framework OSGi è in una condizione di competizione con il contesto runner di test di JUnit e, solitamente, il corridore di prova Junit vince quella gara, eseguendo i test prima che il riferimento al servizio richiesto venga iniettato.
Per risolvere questa situazione, è necessario che il test Junit attenda che il runtime di OSGi esegua il proprio lavoro. Ho risolto questo problema utilizzando CountDownLatch, che è inizializzato sul numero di servizi dipendenti richiesti nel test. Quindi tutti i metodi di iniezione delle dipendenze eseguono il conto alla rovescia e quando sono tutti terminati, il test inizierà. Il codice è simile al seguente:
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();
}
Nota che il riferimento fooService
deve essere statico per consentire la condivisione il riferimento al servizio tra l'OSGi ed i contesti di esecuzione JUnit. CountDownLatch fornisce un meccanismo di sincronizzazione di alto livello per la pubblicazione sicura di questo riferimento condiviso.
Poi, un controllo delle dipendenze deve essere aggiunto prima della esecuzione del test:
@Before
public void dependencyCheck() {
// Wait for OSGi dependencies
try {
dependencyLatch.await(10, TimeUnit.SECONDS);
// Dependencies fulfilled
} catch (InterruptedException ex) {
fail("OSGi dependencies unfulfilled");
}
}
In questo modo il quadro Junit attende il servizio OSGi DS per iniettare le dipendenze o non dopo il timeout.
Mi ci è voluto un po 'di tempo per capire completamente questo. Spero che in futuro risparmi un po 'di mal di testa nei confronti degli altri programmatori.
Certo, questa è l'opzione "Esegui come plug-in JUnit" che ho menzionato, ma non sembra essere sufficiente per ottenere i Servizi dichiarativi iniettati. cioè dove dichiari i metodi di legame? C'è anche la domanda sul contesto. L'iniezione avverrà nel contesto di Junit? Se è così, come funziona quel meccanismo? – maasg
Lo stesso che usi DS nell'applicazione. È necessario aggiungere il pacchetto DS, questo esegue la scansione di altri bundle mentre vengono caricati e gestisce il cablaggio. I binding di DS sono dichiarati nel componente xml in OSGI-INF nel jar del bundle. Vedi http://www.vogella.de/articles/OSGi/article.html#declarativeservices_run per una spiegazione sull'uso di DS nei progetti Plugin di Eclipse. HTH – earcam
Grazie per il suggerimento. I metodi di iniezione di DS non vengono richiamati nel contesto dell'esecuzione del plug-in di Junit. Il mio OSG-INF li dichiara correttamente. – maasg