5

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
EGHDK
  • 17,818
  • 45
  • 129
  • 204
  • What version of Robolectric is this? – EpicPandaForce Jul 21 '17 at 08:13
  • @EpicPandaForce I am currently using 3.0 of robolectric, but I'm okay to use any version 3.0 and above. – EGHDK Jul 21 '17 at 13:39
  • Do you have a custom application class that Robolectric calls and then that class calls Realm.init(Context) during the test? – EpicPandaForce Jul 21 '17 at 14:13
  • @EpicPandaForce 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. – EGHDK Jul 21 '17 at 14:56
  • I think your test is calling `Realm.init(context)` and in unit test setting you should not call that method – EpicPandaForce Jul 21 '17 at 15:12
  • @EpicPandaForce 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? – EGHDK Jul 21 '17 at 16:50
  • `testOptions.unitTests.includeAndroidResources true` – EpicPandaForce May 27 '18 at 16:43

1 Answers1

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

David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • 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. – EGHDK Jul 23 '17 at 09:24
  • 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? – EGHDK Jul 23 '17 at 09:30
  • @EGHDK 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. – David Rawson Jul 23 '17 at 09:49
  • `@Config(application = EmptyApplication.class, manifest="src/main/AndroidManifest.xml", sdk = 21)` – David Rawson Jul 23 '17 at 09:52
  • 1
    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! – EGHDK Jul 23 '17 at 10:11
  • @EGHDK 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. – David Rawson Jul 23 '17 at 20:38
  • 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 again – EGHDK Jul 24 '17 at 11:12
  • 1
    There's no need to create an empty application class as you can simply us `application = android.app.Application.class` – appmattus Feb 05 '18 at 08:47
  • Useful Robolectric link, It is solved my problem of getting resources – Rakshith Kumar Sep 04 '19 at 11:39