I have looked quite a bit for a solution for this (few days) and have not come to a solution yet. Basically, for my unit tests using Robolectric, I keep getting Resources$NotFoundException when trying to inflate resources from a dependency (pulled in as an aar). Heres the setup:
build.gradle (project level)
// Top Level buildscript { apply from: "${System.getenv('MY_REPOS')}", to: buildscript println("REPOS: ${repositories.names}") dependencies { classpath "com.android.tools.build:gradle:3.3.2" } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
build.gradle (app)
plugins { id 'com.android.application' } android { compileSdkVersion 28 defaultConfig { applicationId "com.me.myapplication" minSdkVersion 18 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } testOptions { animationsDisabled true unitTests { includeAndroidResources = true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation 'com.me.android:thewidget:4.0.0' // pulled from private repo implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.navigation:navigation-fragment:2.2.2' implementation 'androidx.navigation:navigation-ui:2.2.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation("com.google.guava:guava:27.0-jre") { exclude group: 'com.google.guava', module: 'failureaccess' } //UnitTests testImplementation 'junit:junit:4.13' testImplementation 'org.robolectric:robolectric:4.3.1' testImplementation 'org.robolectric:android-all:9-robolectric-4913185-2' }
I am using distributionUrl=https://services.gradle.org/distributions/gradle-4.10.3-all.zip
in my gradle-wrapper.properties
and my gradle properties:
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 android.useAndroidX=true android.enableJetifier=true android.enableUnitTestBinaryResources = true //tried with and without this set android.enableAapt2 = false // same here with and without this here
Then its the default blank activity template that comes in Android Studio 4.1.2
. So the only thing touched is the main main activity:
package com.me.myapplication; import android.os.Bundle; import com.me.thewidget.MyOtherView; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } public void testDialogSetup() { MyOtherView myView = new MyOtherView(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
So the issue is with the MyOtherView
and when it inflates the view inside this class. So in MyOtherView
it throws the exception in the test when it hits this line:
... inflater.inflate(layout.my_view, this); ...
As for the test itself:
package com.me.myapplication; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> */ @RunWith(RobolectricTestRunner.class) public class ExampleUnitTest { MainActivity activity; @Before public void setup() { this.activity = Robolectric.buildActivity(MainActivity.class).get(); } @Test public void simpleTest() { activity.testDialogSetup(); // not doing anything yet since it throws the error here } }
I’ve tried invalidating/restarting, clearing cache, I’ve tried different versions of gradle build tools and with the distribution. Everything I read shows to just have the includeAndroidResources
flag set to true but I have that, and I have already tried with/without enableUnitTestBinaryResources
as well as enableAapt2
…
ANY help is appreciated since I have been killing myself trying to get this working. I would think its something simple but… I’m lost here. Its like it can’t see the dependency (com.me.android:thewidget:4.0.0, MyOtherView) resources at all.
Advertisement
Answer
Alright all, I figured it out (actually a colleague did). I added the robolectric.properties file to the src/test/resources area. in the file I had to put:
sdk=28 qualifiers=w1004dp-h654dp
I hope this helps someone down the road.