Android Studio - Robolectric:android.content.res.Resources$NotFoundException:没有这个标签com.my.app:string/app_name。

11

这个问题我似乎无法解决,我已经阅读了大约三到四十篇文章和帖子来尝试解决它。我在下面概述了所有内容。

基本上问题是:我遇到的问题是Robolectric的缺陷吗?还是有些小步骤我忽略了,或者我有一些奇怪的插件组合。任何关于此的指导都将不胜感激。

Windows 7 版本:

  • Gradle 2.7
  • Android Studio 1.3.2
  • Robolectric 3.0
  • Roboguice 3.+

项目依赖项:

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
    classpath "com.newrelic.agent.android:agent-gradle-plugin:4.244.0"
    classpath 'com.github.triplet.gradle:play-publisher:1.1.2'
    classpath 'org.moallemi.gradle.advanced-build-version:gradle-plugin:1.5.0'
}

应用程序依赖项

import org.moallemi.gradle.internal.VersionCodeType

apply plugin: 'com.android.application'
apply plugin: 'newrelic'
apply plugin: 'com.github.triplet.play'
apply plugin: 'org.moallemi.advanced-build-version'

android {
def SERVICE_ACCOUNT = “account”;
def P12_KEY = file('mykey.p12')

signingConfigs {
    releaseConfig {
…
    }
}

compileSdkVersion 22
buildToolsVersion '22.0.1'

advancedVersioning {
    nameOptions {
        versionMajor 6
        versionMinor advancedVersioning.versionCode
    }
    codeOptions {
        versionCodeType VersionCodeType.AUTO_INCREMENT_ONE_STEP
    }
}

defaultConfig {
    applicationId "com.my.app ="
    minSdkVersion 15
    targetSdkVersion 22
    versionCode = advancedVersioning.versionCode
    versionName = advancedVersioning.versionName
}

buildTypes {
    def STRING = "String"
    def URL = "URL"
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.releaseConfig
    }
    staging {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    development {
        minifyEnabled false
    }
    debug {
        minifyEnabled false
    }
}
testOptions {
    unitTests.returnDefaultValues = true
}
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.google.android.gms:play-services:4.2.+'

    compile(name: 'library-release', ext: 'aar')

    compile 'com.squareup.okhttp:okhttp:2.4.0'
    compile 'com.google.code.gson:gson:2.3.1'
    compile 'org.roboguice:roboguice:3.+'
    provided 'org.roboguice:roboblender:3.+'

    testCompile 'junit:junit:4.12'
    testCompile 'org.mockito:mockito-core:1.10.19'
    testCompile "org.robolectric:robolectric:3.0"
}

repositories {
flatDir {
    dirs 'libs'
}
}

自定义 Gradle 运行器

public class M1stRoboelectricGradleTestRunner extends RobolectricTestRunner {
public M1stRoboelectricGradleTestRunner(Class<?> testClass) throws InitializationError {
    super(testClass);
    String buildVariant = (BuildConfig.FLAVOR.isEmpty()
            ? "" : BuildConfig.FLAVOR+ "/") + BuildConfig.BUILD_TYPE;
    String intermediatesPath = BuildConfig.class.getResource("")
            .toString().replace("file:", "");
    intermediatesPath = intermediatesPath
            .substring(0, intermediatesPath.indexOf("/classes"));

    System.setProperty("android.package",
            BuildConfig.APPLICATION_ID);
    System.setProperty("android.manifest",
            intermediatesPath + "/manifests/full/"
                    + buildVariant + "/AndroidManifest.xml");
    System.setProperty("android.resources",
            intermediatesPath + "/res/merged/" + buildVariant);
    System.setProperty("android.assets",
            intermediatesPath + "/assets/" + buildVariant);
}

@Override protected AndroidManifest getAppManifest(Config config) {

    String manifestProperty = System.getProperty("android.manifest");
    String resProperty = System.getProperty("android.resources");
    String assetsProperty = System.getProperty("android.assets");
    AndroidManifest manifest = new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty),
            Fs.fileFromPath(assetsProperty)){
    };
    manifest.setPackageName("com.my.app");
    return manifest;
}
}

测试类

@RunWith(M1stRoboelectricGradleTestRunner.class)
public class MainActivityTest {
    private MainActivity mActivity;
    private Button mButton;
    private TextView mTextView;

@Before
public void setup() {

    mActivity = Robolectric.buildActivity(
            MainActivity.class).create().get();
    mButton = (Button) mActivity.findViewById(R.id.signInButton);
    mTextView = (TextView) mActivity.findViewById(R.id.linkContact);
}
问题:下面这行代码导致了错误:
 mActivity = Robolectric.buildActivity(
    MainActivity.class).create().get();

起初,我尝试使用默认的robolectricGradleTestRunner,但不断收到ResourceNotFound com.my.app :: string / app_name未找到的消息。在浏览了大量的文章和博客之后,我偶然发现了这个链接,通过实现自定义运行程序,我终于解决了app_name问题,至少在某种程度上解决了。

  • 如果我在测试类上使用@config(sdk=21),我会收到最初收到的错误:

    android.content.res.Resources$NotFoundException: no such label com.my.app:string/app_name at org.robolectric.util.ActivityController.getActivityTitle(ActivityController.java:104) at org.robolectric.util.ActivityController.attach(ActivityController.java:49) at org.robolectric.util.ActivityController$1.run(ActivityController.java:121) at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:304) at org.robolectric.shadows.CoreShadowsAdapter$2.runPaused(CoreShadowsAdapter.java:45) at org.robolectric.util.ActivityController.create(ActivityController.java:118) at org.robolectric.util.ActivityController.create(ActivityController.java:129) at org.members1st.mobile.MainActivityTest.setup(MainActivityTest.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

  • 如果我不更改SDK版本,会得到Robolectric不支持API 22的错误信息。

  • 到目前为止,我已尝试:

    1. 根据这个 robolectric讨论串的建议,创建一个自定义的BuildConfig并将其传递进去。
    2. 根据这个讨论串的建议,在@config中设置packageName。
    3. 重载new ApplicationManifest以返回api level。
    4. 在Gradle文件中将targetSdk设置为21。
    5. 之前步骤的几乎每种组合结果都会产生相同的错误。
    6. 确认app_name在测试构建生成的values.xml资源文件中存在

    7. 我尝试使用

      mActivity = Robolectric.setupActivity(MainActivity.class);

    而不是

    mActivity = Robolectric.buildActivity(
        MainActivity.class).create().get();
    

    运行时,正常的单元测试工作。


    提示:尝试正确地格式化你的问题,并将实际问题放在顶部。 - natario
    很棒的提示 - 你有什么更好的措辞建议吗? - aminner
    这是编辑错误还是你的 build.gradle 真的有 applicationId "com.my.app =" - Eugen Martynov
    那只是一个错误,抱歉。我不得不对文件进行清理。 - aminner
    2个回答

    9

    您尝试过吗

    @RunWith(RobolectricGradleTestRunner.class)
    @Config(constants = BuildConfig.class, sdk=21, packageName="com.my.app")
    public class MainActivityTest
    

    是的 - 我曾尝试过那个,结果发现我犯了一个简单愚蠢的错误。packageName 不是 applicationId,虽然在我看到的所有示例中它们都是相同的,所以我没有放在心上 - 作为最后一招的一部分进行了更改,结果运行了。这是我自己超级愚蠢的错误。 - aminner
    sdk=21 的目的是什么? - IgorGanapolsky
    告诉Robolectric针对Android sdk 21运行测试,否则它将使用gradle文件中定义的targetSdkVersion。 Robolectric 3.0不支持sdk 22。 - Steve C

    2

    所以,对于我来说,这个问题的解决方案让我感到非常惊讶,但希望它能帮助其他人。

    packageName(包名)与applicationId(应用ID)并不相同。在大多数示例中,它们是相同的,因此我没有注意到它们之间的区别,直到我决定尝试一下。

    在上面的例子中,包名实际上是org.my.app,但我的应用ID是com.my.app。

    一旦进行了更改,一切都运行得很好。这是一个新手错误!


    packageName 在 build.gradle 中与 applicationId 相同。 - IgorGanapolsky

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接