Robolectric with new Android unit test support

1,051 views
Skip to first unread message

Andreas

unread,
Mar 3, 2015, 2:19:48 AM3/3/15
to robol...@googlegroups.com
Hi all.

I'm working on a fairly complex project that involves many build types and flavours.

Up until now we've been using fairly old versions of Gradle and Android Studio together with a few third party plugins to run Robolectric tests command line and from the IDE (JCAndK, evant).
That all worked fine.

Now we've upgraded to latest AS (1.1), latest Android Gradle (1.1.2) and latest Robolectric (2.4, Gradle plugin 1.0.1).

The plain Java Unit tests works great now in the IDE and command line, but any tests depending on Robolectric are broken for us.

What we have noticed is that the tests *only* run when the following are added to the test configuration VM options,

-Dandroid.manifest="<path>/AndroidManifest.xml" -Dandroid.resources="<path>/res" -Dandroid.package="our.app.com" -Dandroid.assets="<path>/assets" 

I don't really understand how and when this gets added to the configuration, but it seems fairly random and most of the time we have to copy and paste it manually into the test config (Edit Configurations for the test). (We run the tests via the IDE "Run", as per convention - nothing strange).
Also, it doesn't run at all command line any more.

It either fails because it can't find our "TestApplication" class that lives in the same package as the real app and overrides various dependencies for test, or because it can't find resources (such as android.content.res.Resources$NotFoundException: unknown resource 2131296463). All of which worked fine before and works fine in the IDE with the above manual hack.

I've tested to bring this down to barebones for the Gradle config for test,

apply plugin: 'org.robolectric'
testCompile 'org.robolectric:robolectric:2.4'

Still the same issues.

Could someone explain how the manifest/resource/package/assets stuff gets setup and what triggers it? What could we be missing in our setup? Is this related to build types and flavors? Plan JUnit tests run fine in all the combos, so seems to be Robolectric specific issue.

On another note - we are extending the RobolectricTestRunner purely to override the Maven repository settings as we're behind a company firewall and have to use their Maven proxies.
In 2.3, we could override 'configureMaven' in the test runner to do this, but this method does not exist anymore in 2.4 and it seems to be hidden behind a few layers of code.
How can we configure the Maven repo Robolectric should fetch from in 2.4?

Thanks in advance

Nico Küchler

unread,
Mar 3, 2015, 7:58:07 AM3/3/15
to robol...@googlegroups.com
I wrote a step by step guide how to use robolectric with new unit test plugin and created some example projects. Maybe some of your aspects (e.g. AndroidManifest.xml location) is explained there. If you have still some issues, best would be to create sample which shows your setup with build types and flavors.

Erich Douglass

unread,
Mar 3, 2015, 1:42:28 PM3/3/15
to robol...@googlegroups.com
The android properties you mentioned were being added by the android-studio-unit-test-plugin. Robolectric uses those properties to find assets, resources, etc. Without those settings, you'll run into the "Resources$NotFoundException" that appears in your stacktrace. The robolectric-gradle-plugin was upated to pull those values out of the gradle configuration, but it only works on the command line.

For now, you'll need to create a custom test runner to specify those values. Unfortunately, there's no good way to pull those values out of the environment, so you'll need to hard-code them for your app.

I'm still looking for a good way to easily support robolectric in android studio so you don't have to have a custom test runner. I was thinking about updating android-studio-unit-test-plugin to continue to support robolectric, but I'm not sure how well it works in AS 1.1.

Andreas

unread,
Mar 4, 2015, 12:18:19 AM3/4/15
to robol...@googlegroups.com
Hi Nico.

Thanks - I had a look and it did put me in the right direction. However, your examples do not cater for having manifests and resources for each build type and flavor that gets merged during build time. That requires a bit more complex getAppManifest implementation that uses BuildConfig flags (BUILD_TYPE, FLAVOR) to figure out where to look for manifests, resources, etc.

Cheers

Andreas

unread,
Mar 4, 2015, 12:19:42 AM3/4/15
to robol...@googlegroups.com
Hi Erich.

I see - well now I've gotten rid of the plugins altogether and simply use my own manifest implementation in a custom test runner as Nico suggested. That works well in the IDE as well.

Thanks

Nico Küchler

unread,
Mar 4, 2015, 5:01:28 AM3/4/15
to robol...@googlegroups.com
Your are correct. I'm not sure if I can access get the current build type and/or flavor at runtime. With this information it would be possible to point to the correct AndroidManifest.xml Another issue is that we point to the src/main/AndoridManifest.xml but we should use build/intermediates/manifests/**/AndroidManifest.xml which is a merged version.

Andreas

unread,
Mar 4, 2015, 5:08:52 AM3/4/15
to robol...@googlegroups.com
You can use BuildConfig to access that info at run time - that's what I'm using now to do this dynamically. And yes, I also use the generated output in build and not src.

Nico Küchler

unread,
Mar 4, 2015, 5:14:39 AM3/4/15
to robol...@googlegroups.com
Thanks for that advice. I will change this part to include the correct AndroidManifest.xml

Nico Küchler

unread,
Mar 4, 2015, 11:51:53 AM3/4/15
to robol...@googlegroups.com
@Andreas can you show an example please?

when i use the "correct" AndroidManifest.xml robolectric search some stuff at wrong location 
java.lang.RuntimeException: ./app/build/intermediates/manifests/full/debug/res/values is not a directory

Andreas

unread,
Mar 4, 2015, 10:20:47 PM3/4/15
to robol...@googlegroups.com
You need to take different working directories into account - Android Studio and command line execute in the root / app module respectively.
Also, your example is only using the build type - there's no flavor in the path (which is correct assuming you only have one flavor, but incorrect if you have at least 2)

            String root = new File(".").getAbsolutePath().endsWith("<root-module-name>/.") ? "app/" : "";
            String manifestPath =
                    root + "build/intermediates/manifests/full/" + BuildConfig.FLAVOR + "/" + BuildConfig.BUILD_TYPE +
                            "/AndroidManifest.xml";
            String resDir = root + "build/intermediates/res/" + BuildConfig.FLAVOR + "/" + BuildConfig.BUILD_TYPE;
            String assetsDir = root + "build/intermediates/assets/" + BuildConfig.FLAVOR + "/" + BuildConfig.BUILD_TYPE;

            androidManifest = createAppManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir),
                    Fs.fileFromPath(assetsDir));
            androidManifest.setPackageName(BuildConfig.APPLICATION_ID);

Nico Küchler

unread,
Mar 5, 2015, 12:47:26 AM3/5/15
to robol...@googlegroups.com
Do you use libraries like support-v4 or appcompat? 

I managed also to set all paths to the correct location. Now it starts to be funny because the test-project-properties could not be found anymore so that I miss the stuff from libraries. This can be fixed when you replace the AndroidManifest class with a custom one who load the test-project.properties from a known path. But then I get still some inflation errors like android.view.InflateException: XML file ./app/build/intermediates/res/debug/layout/abc_screen_toolbar.xml line #-1 (sorry, not yet implemented): Error inflating class android.support.v7.widget.Toolbar

Looks like it is not so easy to use correct AndroidManifest.

Moiz Zuberi

unread,
Sep 3, 2015, 5:31:57 PM9/3/15
to Robolectric
Hi Nico,

Did u solve the issue? I am facing the exact same problem as you.

I have even posted a question to stackoverflow.
Reply all
Reply to author
Forward
0 new messages