Android - Testing a string resource with Robolectric
Asked Answered
S

1

6

I just want to test that getting a String resource equals what I think it should equal. My issue seems to be that I have Realm in my project. I know that Robolectric doesn't support Realm (it states it in the documentation), but I'm not invoking Realm at all, so I feel like there might be a way to do this.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import static org.junit.Assert.assertEquals;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, manifest = "app/src/main/AndroidManifest.xml")
public class ResourceTester {

    @Test
    public void testingString() {
        String resourceString = RuntimeEnvironment.application.getString(R.string.app_name);
        assertEquals(resourceString, "Yeah");
    }

}

It does look like it IS trying to invoke Realm

java.lang.UnsatisfiedLinkError: Can't load library: 
/var/folders/3x/ddxtg5fs1hxgqrp6h63vsc140000gp/T/android-tmp-
robolectric3612430387389787158/app_lib/librealm-jni.dylib.3.5.0

EDIT: I tried some more things, and it seems like setting the manifestin the @Config annotation is the issue, but then I get a android.content.res.Resources$NotFoundException: unknown resource 2131362072

Any other thoughts? Can I make another Application class where Realm isn't called? How would the /test directory know that?

EDIT FOR DAVID:

I tried this:

@RunWith(RobolectricGradleTestRunner.class)
@Config(application = TestingApplication.class, constants = BuildConfig.class, sdk = 21)
public class ResourceTester {
    @Test
    public void newTestingTests() throws Exception {
        String appName = RuntimeEnvironment.application.getString(R.string.app_name);
    }
}

but I get a:

android.content.res.Resources$NotFoundException: unknown resource 2131362072

If I change it to

@RunWith(RobolectricTestRunner.class)
//@RunWith(RobolectricGradleTestRunner.class)
@Config(application = TestingApplication.class, constants = BuildConfig.class, sdk = 21)
public class ResourceTester {
    @Test
    public void newTestingTests() throws Exception {
        String appName = RuntimeEnvironment.application.getString(R.string.app_name);
    }
}

I get

WARNING: No manifest file found at ./AndroidManifest.xml.Falling back to the Android OS resources only.
To remove this warning, annotate your test class with @Config(manifest=Config.NONE).

android.content.res.Resources$NotFoundException: unknown resource 2131362072
Selfinduced answered 20/7, 2017 at 22:54 Comment(7)
What version of Robolectric is this?Pail
@Pail I am currently using 3.0 of robolectric, but I'm okay to use any version 3.0 and above.Selfinduced
Do you have a custom application class that Robolectric calls and then that class calls Realm.init(Context) during the test?Pail
@Pail I think the issue might be that I'm calling RuntimeEnvironment.application.getString() and I include manifest = "app/src/main/AndroidManifest.xml" which declares my custom application class.Selfinduced
I think your test is calling Realm.init(context) and in unit test setting you should not call that methodPail
@Pail how do I not call that? Should I not use RuntimeEnvironment.application or is it that my manifest is defined and it's trying to load application class?Selfinduced
testOptions.unitTests.includeAndroidResources truePail
K
12

If you have a heavyweight Application class (e.g., with dependencies on Realm, Crashlytics etc.) and your unit tests do not refer to these you can use android.app.Application as your Application class in the config:

@RunWith(RobolectricTestRunner.class)
@Config(application = android.app.Application.class, manifest="src/main/AndroidManifest.xml", sdk = 23)
public class ResourceTester {

Also make sure you have Working Directory set to $MODULE_DIR$ if you are using Mac or Linux as per the getting started instructions

module dir in working directory

Kip answered 23/7, 2017 at 4:28 Comment(9)
hmm... I feel like I'm closer now. Check my edits. Also, I already added the $MODULE_DIRS$. Thanks for the reminder about it though.Selfinduced
Is there any way to debug this. For example... check which resources/package/directory it loaded in the test, vs where my string resource actually lies?Selfinduced
@Selfinduced can you add in the manifest in the arguments for the test runner? Should be app/src/main/AndroidManifest.xml or src/main/AndroidManifest.xml. You'll have to restart Android Studio I think if you've changed module directory. Get rid of the constants = Build.config if you are using a custom Application for testing. So please stick as close as possible to the code I put in my example.Kip
@Config(application = EmptyApplication.class, manifest="src/main/AndroidManifest.xml", sdk = 21)Kip
That didn't work... BUT, this did! @Config(application = TestingApplication.class, constants = BuildConfig.class, sdk = 21, packageName = "com.myapp.app") I think after getting the TestingApplication.class defined, and modifying the packageName to actually be the java package name and not the application id (they are different because of my different build variants), then it worked! Thanks so much! This robolectric stuff sure is confusing!Selfinduced
@Selfinduced okay glad it worked. The code I put in the example worked in my project (no build variants) - I guess if you have build variants it is different.Kip
Yeah, I think it really has to do with what the application id is and the package is. Most of the time it's the same, but once you introduce variants it changes it up. Didn't think it made a difference (in terms of robolectric being able to figure it out), but I was wrong. Thanks againSelfinduced
There's no need to create an empty application class as you can simply us application = android.app.Application.classDow
Useful Robolectric link, It is solved my problem of getting resourcesJar

© 2022 - 2024 — McMap. All rights reserved.