2013-05-14 15 views
10

Ho generato una libreria nativa utilizzando ndk-build che sono in grado di caricare e utilizzare con la mia applicazione Android. Tuttavia, voglio scrivere alcuni test contro questa parte della mia app.Caricamento di una libreria nativa in un test JUnit Android

Quando si chiama la funzione nativa nel mio test, ricevo questo messaggio di eccezione:

java.lang.UnsatisfiedLinkError: no process in java.library.path 

... dove process è la mia libreria nativa di importare, di nome libprocess.so.

Sto usando Roboelectric per i miei test e sto eseguendo questo particolare con RobolectricTestRunner, se fa la differenza.

Come posso ottenere il mio progetto di test per "vedere" la libreria nativa?


Edit: Sto caricamento della libreria nella mia app in questo modo:

static { 
    System.loadLibrary("process"); 
} 
public static native int[] process(double[][] data); 

chiamando Process.process(array) funziona bene in app (la libreria viene caricata), ma non riesce quando viene eseguito da i test con l'eccezione sopra indicata.


Edit 2: se ho impostato -Djava.library.path="<the directory of libprocess.so>" come argomento VM, quindi:

System.out.println(System.getProperty("java.library.path")); 

vuol mostrare il percorso ho impostato, ma ho ancora ottenere la stessa eccezione. Sto impostando la directory come:

<project-name>/libs/x86 

... ma come un percorso assoluto.

+0

Avete il vostro nome pacchetto corretto? Come stai caricando la tua libreria? –

+0

Ho aggiunto alla mia domanda, vedi sopra. – blork

+0

Verificheresti con questo: '-Djava.library.path =" "'? –

risposta

1

Sono passato allo stile di test predefinito (utilizzando ActivityUnitTestCase anziché RoboElectric) e ora funziona correttamente. È un peccato dover sacrificare la velocità del test in esecuzione, ma i test sull'emulatore funzionano davvero. Si potrebbe anche creare una classe ombra per la classe JNI, come dettagliato qui:

Robolectric tanks on Application objects that load JNI libraries. Can I get a workaround?

Forse compilare la libreria per la mia macchina avrebbe funzionato, ma non ho potuto trascorrere più tempo su di esso.

+0

Vedere: https://github.com/robolectric/robolectric/issues/1171 –

1

Nel caso in cui, per chiunque altro cerchi le soluzioni, il numero è un modo per impostare correttamente il percorso di ricerca lib per i test JUnit (anche se non sono ancora riuscito a eseguire correttamente i test, insieme diverso di questioni):

È necessità di mettere il percorso nella variabile d'ambiente LD_LIBRARY_PATH (o PATH su Windows). Ho avuto la stessa esperienza: ho impostato il java.library.path prima, ma apparentemente non influenza il comportamento del caricatore nativo in alcun modo.

Ti invitiamo a dare un'occhiata a my answer here se avete bisogno di informazioni su come farlo con Gradle/Android Studio

3

Per chi ancora alla ricerca, blork avuto l'idea giusta - è necessario compilare le librerie native per la tua piattaforma 'nativa' (Windows, Linux, Mac). L'NDK di Android crea librerie per la piattaforma Android (file .so - potrebbe funzionare anche su Linux), ed è per questo che non ci sono problemi in esecuzione in Activity Test Cases (perché carica un'istanza Android).

Per ottenere i test JUnit di livello basso, Hella veloce in esecuzione, è necessario supportare la JVM. Su Windows, questo potrebbe creare DLL, su Apple, sta creando i dylibs (assumendo le librerie condivise).

Ho appena completato un esempio nel mio repository android-ndk-swig-example (https://github.com/sureshjoshi/android-ndk-swig-example/issues/9).

In sostanza, nei miei CMakeLists, ho aggiunto un avvertimento di Apple:

# Need to create the .dylib and .jnilib files in order to run JUnit tests 
if (APPLE) 
    # Ensure jni.h is found 
    find_package(JNI REQUIRED) 
    include_directories(${JAVA_INCLUDE_PATH}) 

E poi mi assicuro Gradle corre per i test unitari, ma utilizzando il sistema Mac costruire (non NDK).

def osxDir = projectDir.absolutePath + '/.externalNativeBuild/cmake/debug/osx/' 

task createBuildDir() { 
    def folder = new File(osxDir) 
    if (!folder.exists()) { 
     folder.mkdirs() 
    } 
} 

task runCMake(type: Exec) { 
    dependsOn createBuildDir 
    workingDir osxDir // Jump to future build directory 
    commandLine '/usr/local/bin/cmake' // Path from HomeBrew installation 
    args '../../../../' // Relative path for out-of-source builds 
} 

task runMake(type: Exec) { 
    dependsOn runCMake 
    workingDir osxDir 
    commandLine 'make' 
} 

project.afterEvaluate { 
    // Not sure how much of a hack this is - but it allows CMake/SWIG to run before Android Studio 
    // complains about missing generated files 
    // TODO: Probably need a release hook too? 
    javaPreCompileDebug.dependsOn externalNativeBuildDebug 
    if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) { 
     javaPreCompileDebugAndroidTest.dependsOn runMake 
    } 
} 

CAVEAT TIME !!!

Quando si utilizza questo metodo, tecnicamente non si testano le librerie generate da NDK. Stai testando lo stesso codice, ma compilato usando un compilatore diverso (msvc, xcode, gcc, clang, qualsiasi cosa tu usi sull'host).

Ciò significa in pratica che la maggior parte dei risultati del test sarà valida, tranne quando si incontrano problemi causati da stranezze di ciascun compilatore, implementazioni STL, ecc. Questo non è così male come lo era 10 + anni fa, ma non si può dire con certezza al 100% che i risultati del test di JUnit con le librerie host siano identici alle librerie Android. Puoi dire che è ragionevolmente vicino, però.

Quindi, a meno che non si eseguano i test dell'unità nativa utilizzando l'NDK di Android per ciascuna architettura supportata, non si può nemmeno dire nulla sulla certezza ... Quindi prendi quello che vuoi da esso.

Un approccio eccessivo (ma davvero interessante se automatizzato) sarebbe quello di scrivere i test dell'unità nativi, ma li fai (Google Test, Catch, ecc.), Quindi compila ed esegui le tue librerie nativi e test unitari con l'NDK di Android ogni architettura. Ciò fornisce la copertura C/C++ tra le potenziali architetture di destinazione.

Da qui, è possibile utilizzare le librerie host summenzionate con JUnit per testare rapidamente il livello JNI interagendo con la libreria nativa. Nel tuo sistema CI, dovresti comunque eseguire questi stessi test unitari, ma come test di strumenti Android (o qualcos'altro che esegue un ambiente Android emulato).

Come per tutto, ovunque si disponga di un'interfaccia, è possibile creare mock - ma ad un certo punto, avrete bisogno anche di test di sistema/funzionali/di integrazione.

Aggiornamento:

più completa spiegazione di cui sopra in un articolo del blog (http://www.sureshjoshi.com/mobile/android-junit-native-libraries/)

Problemi correlati