在Android JUnit测试中加载本机库

blo*_*ork 15 java junit android android-ndk

我已经生成了一个本机库ndk-build,我可以在我的Android应用程序中加载和使用它.但是,我想针对我的应用程序的这一部分编写一些测试.

在我的测试中调用本机函数时,我收到此异常消息:

java.lang.UnsatisfiedLinkError: no process in java.library.path
Run Code Online (Sandbox Code Playgroud)

... process我要导入的本地库在哪里命名libprocess.so.

我正在使用Roboelectric进行测试,并运行这个特殊的测试RobolectricTestRunner,如果它有所作为.

如何让我的测试项目"看到"本机库?


编辑: 我正在我的应用程序中加载库,如下所示:

static {
    System.loadLibrary("process");
}
public static native int[] process(double[][] data);
Run Code Online (Sandbox Code Playgroud)

调用Process.process(array)在应用程序中正常工作(库已加载),但在从上面给出的异常的测试运行时失败.


编辑2: 如果我设置-Djava.library.path="<the directory of libprocess.so>"为VM参数,则:

System.out.println(System.getProperty("java.library.path"));
Run Code Online (Sandbox Code Playgroud)

确实显示了我设置的路径,但我仍然得到相同的异常.我将目录设置为:

<project-name>/libs/x86
Run Code Online (Sandbox Code Playgroud)

......但作为一条绝对的道路.

SJo*_*shi 10

对于仍在寻找的人来说,blork有正确的想法 - 您需要为您的"本机"平台(Windows,Linux,Mac)编译本机库.Android NDK为Android平台构建库(.so文件 - 也可以在Linux上运行),这就是为什么在Activity Test Cases中运行没有问题(因为它加载了一个Android实例).

要使低级别的hella fast JUnit测试运行,您需要支持您的JVM.在Windows上,这可能是在Apple上构建DLL,它正在构建dylib(假设是共享库).

我刚刚在android-ndk-swig-example repo中完成了一个示例(https://github.com/sureshjoshi/android-ndk-swig-example/issues/9).

基本上,在我的CMakeLists中,我添加了一个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})
Run Code Online (Sandbox Code Playgroud)

然后我确保Gradle运行单元测试,但使用Mac构建系统(不是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
    }
 }
Run Code Online (Sandbox Code Playgroud)

CAVEAT TIME !!!

当您使用此方法时,您在技术上不会测试NDK生成的库.您正在测试相同的代码,但使用不同的编译器(msvc,xcode,gcc,clang,无论您在主机上使用什么)编译.

实际上,这意味着大多数测试结果都是有效的 - 除非你遇到由每个编译器的怪癖或STL实现等引起的问题......这并不像10年前那样糟糕,但你不能100%肯定地说,使用主机库的JUnit测试结果与Android库相同.不过,你可以说它相当接近.

再说一次,除非你为每个支持的架构使用Android NDK运行本机单元测试,否则你也无法说出任何关于确定性的信息......所以你要从中获取它的意思.

一种矫枉过正的方法(但是如果自动化的话真的很酷)就是编写你的原生单元测试但是你会这样做(Google Test,Catch等),然后使用每个架构的Android NDK编译和运行你的本机库和单元测试.这为您的潜在目标体系结构提供了C/C++覆盖.

从这里开始,您可以使用前面提到的主机库和JUnit来快速单元测试与您的本机库交互的JNI层.在您的CI系统中,您仍然应该运行这些相同的单元测试 - 但是作为Android Instrumentation测试(或运行模拟Android环境的其他东西).

与所有内容一样,只要有接口,就可以创建模拟 - 但在某些时候,您还需要系统/功能/集成测试.

更新:

博客文章中对上述内容进行了更全面的解释(http://www.sureshjoshi.com/mobile/android-junit-native-libraries/)

  • 为了在 Windows 上获得它,我应该改变什么?(64 位) (2认同)