5

每当我运行单元测试时,当它尝试从自定义 config.xml 文件中检索字符串值时,我都会收到此错误。

背景:

该项目本身是一个库 apk 项目,它使用和引用另一个库 APK 项目。

当项目本身尝试启动一个新对象时会发生错误,该对象是引用的库 apk 项目中包含的超类的子类。

该问题在下面进行了详细说明

因错误而失败的特定代码行是下面定义的静态变量:

  protected static final String ANDROID_CONFIG_ID =  LibraryApplication.getApplication().getString(R.string.api_checkout_config_id_override);

它失败并出现以下错误:

java.lang.NoClassDefFoundError: com/jon/commonlib/R$string

如果您想知道,commonLib 是引用的库 apk。

这是我的单元测试

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, manifest=Config.NONE)
public class TestSearchShows {

    @Test
    public void testSearchJsonFile(){
        EventsTestHelper testHelper = new EventsTestHelper(RuntimeEnvironment.application);

        try {
            ShowsList showList = testHelper.getShowList(new SearchEvent());

            if(showList.getShows().size() < 0){
                Assert.fail("show list is empty");
            }

        } catch (IOException e) {
            e.printStackTrace();
            Assert.fail(e.toString());
        }
    }


}

EventsTestHelper 是名为 NetworkHelper 的超类的子类,如下所示:

public abstract class NetworkHelper<T, P, S> implements NetworkConstants {

protected static final String ANDROID_CONFIG_ID = LibraryApplication.getApplication().getString(R.string.api_checkout_config_id_override);

//other stuff ....

}

我使用最新的 robolectric 3.0 版来运行我的单元测试。

如果我要实时运行代码并调用并启动子类,它工作得很好,没有崩溃

编辑:下面是我的构建 gradle 文件的片段

apply plugin: 'android-sdk-manager'
apply plugin: 'com.android.library'
apply plugin: 'crashlytics'


buildscript {
    repositories {
        jcenter()
        mavenCentral()
        maven { url 'http://download.crashlytics.com/maven' }
        maven { url 'http://www.testfairy.com/maven' }

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.0'
        classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+'
        classpath 'com.crashlytics.tools.gradle:crashlytics-gradle:1.+'
        classpath 'com.testfairy.plugins.gradle:testfairy:1.+'

    }
}

repositories {
    mavenCentral()
    maven { url 'http://download.crashlytics.com/maven' }
    maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    flatDir {
        dirs 'libs'
    }
}

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"
    def package_namespace = "com.jonney.moduleApp"

   defaultConfig {
        minSdkVersion 14
        testApplicationId "com.jonney.moduleApp"
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
 productFlavors {
        //testing {
        //}
        local {
        }
        mock {
        }
        qa {
        }
        //qa4 {
        //}
        production {
        }
    }

    sourceSets {



        local {
            res.srcDir 'build-config/local/res'
        }
        testing {
            res.srcDir 'build-config/testing/res'
        }
        mock {
            res.srcDir 'build-config/mock/res'
        }
        qa {
            res.srcDir 'build-config/qa/res'
        }
        qa4 {
            res.srcDir 'build-config/qa4/res'
        }
        staging {
            res.srcDir 'build-config/staging/res'
            test.java.srcDirs += 'src/main/java'
        }
        production {
            res.srcDir 'build-config/production/res'
            test.java.srcDirs += 'src/main/java'
            test.java.srcDirs += "build/generated/source/r/production"
            test.java.srcDirs += "build/generated/source/buildConfig/production"
        }

    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19.1.+'
    compile 'com.google.code.gson:gson:2.3'
    testCompile('org.robolectric:robolectric:3.0') {
        exclude group: 'commons-logging', module: 'commons-logging'
        exclude group: 'org.apache.httpcomponents', module: 'httpclient'
    }
    compile 'com.fasterxml.jackson:jackson-parent:2.5'
    compile 'com.squareup:otto:1.3.6'
    compile 'com.jakewharton:butterknife:6.1.0'
    compile 'com.sothree.slidinguppanel:library:3.0.0'
    compile 'com.crashlytics.android:crashlytics:1.+'
    compile 'com.mcxiaoke.volley:library-aar:1.0.0'
    compile "joda-time:joda-time:2.4"
    testCompile('junit:junit:4.12') {
        exclude module: 'hamcrest'
        exclude module: 'hamcrest-core'
    }
    testCompile 'org.hamcrest:hamcrest-all:1.3'
    compile 'com.sothree.slidinguppanel:library:3.0.0'
    compile 'com.squareup:otto:1.3.6'
    compile 'com.squareup.okhttp:okhttp:2.3.0'
    testCompile 'org.apache.maven:maven-ant-tasks:2.1.3'

    compile 'com.google.android.gms:play-services:7.0.0'

    compile 'com.android.support:multidex:1.0.0'

    compile(name: 'commonLib 1.0 1', ext: 'aar')
    testCompile(name: 'commonLib-1.0 1', ext: 'aar')
}

编辑:我还尝试手动创建一个任务,为每个依赖项复制 r 类。

    afterEvaluate { project ->
        android.libraryVariants.each { variant ->
            // workaround for missing R class for aar dependencies
            def copyTaskName = "copy${variant.name.capitalize()}AppCompat"
            def copyTaskNameTwo = "copy${variant.name.capitalize()}commonlib"
            task(copyTaskName, type:Copy) {
                dependsOn "process${variant.name.capitalize()}Resources"
                from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
                into { "build/generated/source/r/${variant.dirName}/com/jon/commonlib" }
//                into { "src/test/java/android/support/v7/appcompat" }
                include 'R.java'
                filter { line -> line.contains("package ${package_namespace};") ? 'package android.support.v7.appcompat;' : line }
                outputs.upToDateWhen { false }
            }
            task(copyTaskNameTwo, type:Copy) {
                dependsOn "process${variant.name.capitalize()}Resources"
                from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
                into { "build/generated/source/r/${variant.dirName}/android/support/v7/appcompat" }
//                into { "src/test/java/android/support/v7/appcompat" }
                include 'R.java'
                filter { line -> line.contains("package ${package_namespace};") ? 'package com.jon.commonlib;' : line }
                outputs.upToDateWhen { false }
            }
            System.out.println("adding ${copyTaskName} build/generated/source/r/${variant.dirName}/$package_namespace_path ")
            println("basename =  ${variant.baseName}")
            println("directory name =  ${variant.dirName}")
            tasks.getByName("compile${variant.name.capitalize()}UnitTestJava") dependsOn copyTaskName
        }
    }

亲切的问候

强尼

4

4 回答 4

1

该项目本身是一个库 apk 项目,它使用和引用另一个库 APK 项目。

对于此类项目,存在一个已知问题https://github.com/robolectric/robolectric/issues/1796,但您可以解决它。

基本问题是库项目的 android/gradle 行为,这与应用程序项目不同。它只是忽略从 aar 依赖项生成 R 类。

要解决此问题,您可以提供自己的 R 类,该类已经包含所有依赖项 R 值。这是 appcompat 依赖项的示例

afterEvaluate { project ->
  android.libraryVariants.each { variant ->
    // one line for each aar dependency
    tasks.getByName("assemble${variant.name.capitalize()}").dependsOn copyAppcompat
  }
}

// copy it for each aar dependency and adjust it to your needs
task copyAppcompat(type: Copy) {

  // replace the base package with yours (all after /r/debug/) which contains your R.class
  from 'build/generated/source/r/debug/com/example/core'.replace("/", File.separator)

  // replace the library packages with yours (all after /test/java/) with your aar dependency base package
  into 'src/test/java/android/support/v7/appcompat'.replace("/", File.separator)

  // also replace the package declaration or you will get compile errors
  filter { line -> line.contains('package com.example.core;') ? 'package android.support.v7.appcompat;' : line }
  include 'R.java'
}

可以在https://github.com/nenick/AndroidStudioAndRobolectric/tree/library-with-aar找到带有您的设置的示例项目

于 2015-08-30T08:20:51.027 回答
0

我无法以任何方式重现这一点,但这里有两件事可能会有所帮助。

  • 尝试使用RobolectricGradleTestRunner而不是RobolectricTestRunner
  • 您不需要将其他库放在 testCompile 中。所以我认为你可以安全地删除testCompile(name: 'commonLib-1.0 1', ext: 'aar')

如果您在尝试不同的跑步者后有任何更新,请在评论中告诉我。

于 2015-08-28T10:36:54.413 回答
0

您是否在测试类路径中包含该库?

 dependencies {
    androidTestCompile(<reference to commonLib>)
 }
于 2015-08-19T15:44:50.000 回答
-2

您的图书馆可能与其他图书馆发生冲突,因此尝试解决冲突可能就是问题所在。

于 2015-08-28T07:25:55.577 回答