Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing fragment: I keep getting java.lang.RuntimeException: android.view.InflateException

I was following this codelab about Material Components and after finishing it I thought I should practice writing some instrumentation tests. The app works fine. But I keep getting this error when I run any of the tests:

    java.lang.RuntimeException: android.view.InflateException: Binary XML file line #37: Binary 
    XML file line #37: Error inflating class 
    com.google.android.material.textfield.TextInputLayout
    at androidx.test.runner.MonitoringInstrumentation.runOnMainSync(MonitoringInstrumentation.java:450)
    at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:564)
    at androidx.fragment.app.testing.FragmentScenario.internalLaunch(FragmentScenario.java:300)
    at androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.java:282)
    at com.google.codelabs.mdc.kotlin.shrine.LoginFragmentTest.username_and_password_editTexts_visible(LoginFragmentTest.kt:64)
    at java.lang.reflect.Method.invoke(Native Method)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
    at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1941)
    Caused by: android.view.InflateException: Binary XML file line #37: Binary XML file line #37: Error inflating class com.google.android.material.textfield.TextInputLayout
    Caused by: android.view.InflateException: Binary XML file line #37: Error inflating class com.google.android.material.textfield.TextInputLayout
    Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
    at android.view.LayoutInflater.createView(LayoutInflater.java:645)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:861)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
    at com.google.codelabs.mdc.kotlin.shrine.LoginFragment.onCreateView(LoginFragment.kt:19)
    at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
    at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
    at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
    at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
    at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
    at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
    at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
    at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:317)
    at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:301)
    at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$ActivityScenario(ActivityScenario.java:551)
    at androidx.test.core.app.ActivityScenario$$Lambda$4.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:1959)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6236)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)
    Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).
    at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:248)
    at com.google.android.material.internal.ThemeEnforcement.checkMaterialTheme(ThemeEnforcement.java:222)
    at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:150)
    at com.google.android.material.internal.ThemeEnforcement.obtainTintedStyledAttributes(ThemeEnforcement.java:120)
    at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:424)
    at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:396)
    ... 38 more

    Test running failed: Instrumentation run failed due to 'Process crashed.'

My gradle dependencies:

dependencies {
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.code.gson:gson:2.8.6'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testImplementation 'junit:junit:4.13'
    androidTestImplementation 'androidx.test:core:1.2.0'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test:runner:1.3.0-alpha04'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha04'
    debugImplementation ('androidx.fragment:fragment-testing:1.2.2'){
        exclude group: 'androidx.test', module : 'core'
    }
}

I tried changing the Material dependency's version but with no luck.

My styles file:

    <style name="AppTheme.NoActionBar" parent="Theme.MaterialComponents.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

Fragment layout file:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/loginPageBackgroundColor"
    tools:context=".LoginFragment">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:orientation="vertical"
        android:padding="24dp"
        android:paddingTop="16dp">

        <ImageView
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="48dp"
            android:layout_marginBottom="16dp"
            app:srcCompat="@drawable/shr_logo"
            android:contentDescription="@string/shr_logo_content_description"  />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="132dp"
            android:text="@string/shr_app_name"
            android:textAllCaps="true"
            android:textSize="16sp" />

        <com.google.android.material.textfield.TextInputLayout
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:layout_margin="4dp"
            android:hint="@string/shr_hint_username"
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
            >
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/username_edit_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/password_text_input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="4dp"
            android:hint="@string/shr_hint_password"
            app:errorEnabled="true"
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
            android:inputType="textPassword"
            >
            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/password_edit_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </com.google.android.material.textfield.TextInputLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <com.google.android.material.button.MaterialButton
                android:id="@+id/next_button"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:text = "@string/shr_button_next"
                />
            <com.google.android.material.button.MaterialButton
                android:id="@+id/cancel_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="12dp"
                android:layout_marginRight="12dp"
                android:layout_toStartOf="@id/next_button"
                android:layout_toLeftOf="@id/next_button"
                android:text="@string/shr_button_cancel"
                style="@style/Widget.MaterialComponents.Button.TextButton"
                />
        </RelativeLayout>

        <!-- Snippet from "Add buttons" section goes here. -->

    </LinearLayout>
</ScrollView>

The code on line 37 is the first TextInputLayout

The fragment implementation:

import android.os.Bundle
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.shr_login_fragment.*
import kotlinx.android.synthetic.main.shr_login_fragment.view.*


class LoginFragment : Fragment() {

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.shr_login_fragment, container, false)
        view.next_button.setOnClickListener {
            if(isPasswordValid(password_edit_text.text)){
                view.password_text_input.error = null
                // the false so as to not return back to the login screen again
                (activity as NavigationHost).navigateTo(ProductGridFragment(),false)
            }else{
                view.password_text_input.error = getString(R.string.shr_error_password)
            }
        }
        view.password_edit_text.setOnKeyListener { _, _, _ ->
            if(isPasswordValid(password_edit_text.text)){
                view.password_text_input.error = null
            }
            false
        }
        view.cancel_button.setOnClickListener {
            view.password_edit_text.setText("")
            view.username_edit_text.setText("")
        }
        return view
    }
    private fun isPasswordValid(text: Editable?): Boolean{
        return text!=null && text.length >= 8
    }
}
like image 534
Ahmed Aboelyazeed Avatar asked Dec 10 '22 01:12

Ahmed Aboelyazeed


2 Answers

This was the problem :

Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).

We need to supply the correct style to the fragment test class. In your layout files, there is material component view (TextInputLayout), so we need to use the MaterialComponents theme.

When creating the FragmentTest class, use style arguments:

@RunWith(AndroidJUnit4::class)
class DummyFragmentTest {

    @Test
    fun testing() {
        launchFragmentInContainer<DummyFragment>(factory = object : FragmentFactory() {
            override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
                return DummyFragment()
            }
        }, themeResId = R.style.AppTheme.NoActionBar) // this is your style
    }
}
like image 82
boni octavianus Avatar answered Jan 16 '23 14:01

boni octavianus


Quick and easy way to fix it.

    @Before
    fun setUp() {
        scenario = launchFragment<MyFragment>(themeResId = R.style.Theme_MaterialComponents)
    }
like image 20
Shwarz Andrei Avatar answered Jan 16 '23 16:01

Shwarz Andrei