Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Studio - Robolectric: android.content.res.Resources$NotFoundException: no such label com.my.app:string/app_name

This issue I cannot seem to get rid of, I've gone through probably 3 or 4 dozen articles and threads trying to resolve it. I've outlined everything below.

Basically the question is, is the issue I'm having a flaw with Robolectric? Or is there some small step I’m missing, or I have a weird combination of plugins. Any guidance on this would be greatly appreciated.

Windows 7 Versions:

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

Project Dependencies:

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'
}

App Dependencies

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'
}
}

Custom Gradle Runner

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;
}
}

Test Class

@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);
}

Issue: The following line of code is what is throwing the error:

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

Initially, I attempted to use the default robolectricGradleTestRunner but kept receiving the ResourceNotFound com.my.app::string/app_name not found. After perusing a ridiculous amount of articles and blogs, I came across this and was able to get past it by implementing a custom runner. This solved the app_name issue, sort of.

  1. If on the test class I put @config(sdk = 21) I receive the error I was receiving initially:

    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)

  2. If I leave the SDK alone, I get Robolectric doesn’t support API 22

So far I’ve tried:

  1. Creating a custom BuildConfig and passing that in per recommendations on this robolectric thread.
  2. Setting the packageName in the @config per recommendations on this thread.
  3. Overloading the new ApplicationManifest to send back the api level
  4. Setting the targetSdk to 21 in my Gradle file
  5. Pretty much every combination of the previous steps results in the same error.
  6. Verified that the app_name is in the values.xml resources file generated by the test build

  7. I’ve tried using

    mActivity = Robolectric.setupActivity(MainActivity.class);

Instead of

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

8. Regular unit tests are working when being run.

like image 740
aminner Avatar asked Sep 14 '15 14:09

aminner


1 Answers

Have you tried

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk=21, packageName="com.my.app")
public class MainActivityTest
like image 68
Steve C Avatar answered Oct 03 '22 02:10

Steve C