androidrobolectricandroid-textinputlayoutinstrumented-test

Robolectric test fails when trying to inflate layout that has a TextInputLayout


Android Studio 4.0.1
Robolectric 4.3.1

I am writing a robolectric test and the test will fail with a error below. And seems to be related to the TextInputLayout that can't be inflated. If I remove the TextInputLayout the test will pass ok.

This is the error message I am getting.

android.view.InflateException: Binary XML file line #47: Binary XML file line #47: Error inflating class com.google.android.material.textfield.TextInputLayout
Caused by: android.view.InflateException: Binary XML file line #47: Error inflating class com.google.android.material.textfield.TextInputLayout
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).

The test class itself

@Config(sdk = [Build.VERSION_CODES.O_MR1])
@RunWith(AndroidJUnit4::class)
class CharitiesAdapterTest {

    private lateinit var charitiesAdapter: CharitiesAdapter

    @Before
    fun setUp() {
        charitiesAdapter = CharitiesAdapter()
    }

    @Test
    fun `should create viewHolder`() {
        // Act & Assert
        assertThat(createViewHolder()).isNotNull
    }

    private fun createViewHolder(): CharitiesViewHolder {
        val constraintLayout = ConstraintLayout(ApplicationProvider.getApplicationContext())

        return charitiesAdapter.onCreateViewHolder(constraintLayout, 0)
    }
}

The actual adapter under test

class CharitiesAdapter : RecyclerView.Adapter<CharitiesViewHolder>() {

    private val charitiesList: MutableList<Charity> = mutableListOf()
    private var selectedCharity: (Charity) -> Unit = {}

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharitiesViewHolder {
        val charitiesViewHolder = CharitiesViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.charity_item, parent, false))

        return charitiesViewHolder
    }

    override fun getItemCount(): Int = charitiesList.count()

    override fun onBindViewHolder(holder: CharitiesViewHolder, position: Int) {
        // left blank
    }
}

This is the part of the layout that is having the issue. When removing just the TextInputLayout the test will pass OK

 <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayoutPostcode"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ivLogo">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/editTextPostcode"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </com.google.android.material.textfield.TextInputLayout>
    

This is the style I am using

    <resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

Thanks for any advice


Solution

  • You could configure your tests to use a mock application that uses the app theme as shown below:

    Kotlin Implementation

    class TestApplication : Application() {
    
        override fun onCreate() {
            super.onCreate()
            setTheme(R.style.AppTheme) //or just R.style.Theme_AppCompat
        }
    }
    
    

    Then configure your tests to use this mock application

    @Config(application=TestApplication::class, sdk = [Build.VERSION_CODES.O_MR1])
    @RunWith(AndroidJUnit4::class)
    class CharitiesAdapterTest {
    

    Java Implementation

    public class TestApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            setTheme(R.style.AppTheme); //or just R.style.Theme_AppCompat
        }
    }
    
    

    Then configure your tests to use this mock application

    @Config(application=TestApplication.class, sdk = [Build.VERSION_CODES.O_MR1])
    @RunWith(AndroidJUnit4.class)
    class CharitiesAdapterTest {