Testing with Robolectric - Flavors

In my last blog post, you have learnt how to introduce Robolectric. Unfortunately, when you start using Android flavors, the whole concept starts to collapse.
This second part of my Robolectric series offers you a brief tutorial, deduced from Jason Atwood’s perceptions about Robolectric with flavors, how to master flavors with Robolectric.
Flavors
Widely known, product flavors can be added via Gradle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { applicationId "com.example.sn.myapplication" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } productFlavors { pro { applicationId = "com.example.sn.myapplication.pro" } free { applicationId = "com.example.sn.myapplication.free" } } } |
By the way: Even when Android Studio begs you to cast your product flavors application ids: Don’t do it.
Issue
When you try to run an Robolectric tests, they will fail because your application id cannot be resolved.
1 2 3 4 5 6 7 8 9 10 |
android.content.res.Resources$NotFoundException: no such label com.example.sn.myapplication.free: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.robolectric.util.ActivityController.setup(ActivityController.java:210) at org.robolectric.Robolectric.setupActivity(Robolectric.java:46)Solution |
Fortunately, due to the current Robolectric 3.0 release, you can define a packageName identifier to fix your broken tests.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.example.sn.myapplication; import android.app.Activity; import com.example.sn.myapplication.test.RobolectricTestSetup; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; import static org.junit.Assert.assertEquals; @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = RobolectricTestSetup.SDK_VERSION, packageName ="com.example.sn.myapplication") public class MainActivityTest { private Activity cut; @Before public void setUp() throws Exception { cut = Robolectric.setupActivity(MainActivity.class); } @Test public void assertActivityTitle() throws Exception { String expectedTitle = cut.getString(R.string.app_name); assertEquals("Activity title does not match", expectedTitle, cut.getTitle().toString()); } } |
Test Directories
From a directory structure point of view, flavors are realized by adding additional directories to your source folder. I specified the two flavors “free” and “pro”, so I created their related source folders beside the main directory.
- src/free
- src/pro
Depending on your ‘Build Variants’, the proper flavor directory is highlighted in blue to emphasize which source folders are being checked while programming and considered for device or emulator deployment.

Flavor project src structure
Regarding project structure, beside the test source folders ‘androidTest’ and ‘test‘, you should create test directories matching your product flavor names:
- src/testFree
- src/testPro
Based on your build variants, you can switch between your flavor based test source folders for execution.

Flavor project test structure
Test Class Naming
Generally known, you cannot add two classes with the same name and package identifier in two different flavors, except asset or resource files. Therefore, your test classes’ names must differ.

Flavor project class naming
If you want to auto-create a (flavored) test case, open your desired class and use the Ctrl Shift T shortcut.

Create Flavor Test
After clicking the ‘OK’ button, choose your preferred test (flavor) folder.

Choose Flavor Test Directory
Remark: Depending on your chosen build variant, only the specified flavor test folder will be listed.
Test Scenario
In my case, I wanted to test if my FloatingActionButton’s color is properly customized when applying my pro flavor sources. For your interest: I used the BasicActivity example from Android Studio for this demo.

Basic Activity Android Studio – Deep Pink

Basic Activity Android Studio – Red
Both flavors have in common that there activity title matches in both variants. So I implemented a test, located in src/test/MainActivityTest, to assert all common functionality of both flavors whereas separate test classes are located in src/testFree and src/testPro to assert the FloatingActionButton color behavior.
Test Class
In the end, the flavor test case can be look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.example.sn.myapplication; import android.app.Activity; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.support.design.widget.FloatingActionButton; import com.example.sn.myapplication.test.RobolectricTestSetup; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; import static org.junit.Assert.assertEquals; @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = RobolectricTestSetup.SDK_VERSION, packageName = "com.example.sn.myapplication") public class MainActivityProTest { private static final int RED_COLOR = Color.parseColor("#A2232F"); private Activity cut; @Before public void setUp() throws Exception { cut = Robolectric.setupActivity(MainActivity.class); } @Test public void assertEmailButtonColor() throws Exception { FloatingActionButton mailButton = (FloatingActionButton) cut.findViewById(R.id.fab); ColorStateList list = mailButton.getBackgroundTintList(); int defaultColor = list != null ? list.getDefaultColor() : 0; assertEquals("Color does not match", RED_COLOR, defaultColor); } } |
The crucial line of code is the declaration of a packageName to make Robolectric compatible with flavors.
Summary
You are now capable of adapting your Robolectric test classes for flavors and how your project structure has to be correctly designed to switch between flavors for different test executions.
— Stefan
Comment article
Recent posts






Comments
Stefan Nägele
Hi Diogo,
it’s one of Android flavor’s drawbacks that, up to a certain point, code become redundant. Unfortunately, this flavor behavior reflects on our tests as well.
In the end, it depends on the redundancy (and thereby of the design) of the actual app code.
Diogo
Good example to test the differences between your activities. But as I understand at some point you will start duplicating your tests…