Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FragmentScenario configuration - Binary XML file line, Error inflating class <widget> while testing with espresso

Inflating error while trying to use FragmentScenario with launchFragment and launchFragmentInContainer if using material component in XML.

android.view.InflateException: Binary XML file line #41: Binary XML file line #41: Error inflating class <widget class>
Caused by: android.view.InflateException: Binary XML file line #41: Error inflating class <widget class>
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:334)
at android.view.LayoutInflater.createView(LayoutInflater.java:647)
at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58)
at android.view.LayoutInflater.onCreateView(LayoutInflater.java:720)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
...
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:886)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1227)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1293)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:710)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2063)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1853)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1808)
at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManagerImpl.java:1685)
at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:554)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:308)
at androidx.fragment.app.testing.FragmentScenario$1.perform(FragmentScenario.java:286)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$1$ActivityScenario(ActivityScenario.java:534)
at androidx.test.core.app.ActivityScenario$$Lambda$0.run(Unknown Source:4)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2093)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 5: TypedValue{t=0x2/d=0x7f03009f a=-1}
at android.content.res.TypedArray.getColorStateList(TypedArray.java:538)
at android.widget.TextView.<init>(TextView.java:1214)
at android.widget.Button.<init>(Button.java:166)
at android.widget.Button.<init>(Button.java:141)
at android.widget.Button.<init>(Button.java:117)

Can't inflate XML because there are missing styles.

like image 262
MatPag Avatar asked Mar 19 '19 15:03

MatPag


1 Answers

First of all be sure to have the latest fragment-testing dependency:

debugImplementation "androidx.fragment:fragment-testing:$fragment_version"

Some additional info:

  1. The fix has been published in version 1.1.0-alpha03, so prior versions will not work as described here.
  2. Remember to use debugImplementation or the dependency will not work correctly, thanks to this so answer
  3. If you have errors like "process crashed, "No tests found."" check if this issue can help.

After this you can create Fragments with:

val bundle = Bundle()
.... 
launchFragmentInContainer(bundle, R.style.Theme_AppCompat) {
    YourFragment()
}
//proceed here with espresso testing

Don't forget R.style.Theme_AppCompat otherwise Espresso will crash with the android.view.InflateException error if you use widgets coming from the com.google.android.material:material artifact. Obviously if you need a custom style you can add a new rule to your styles.xml and reference it here.

In my case I had the Navigation component configured so I had to follow the suggestion of the official documentation here to be sure the navController is ok with the lifecycle.

First of all I have create a generic method in my TestFragmentUtils.kt

inline fun <reified F : Fragment> launchFragmentScenario(
    bundle: Bundle?, fragment: F, navController: NavController): FragmentScenario<F> {
    return launchFragmentInContainer(bundle, R.style.Theme_AppCompat) {
        fragment.also { fragment ->
            fragment.viewLifecycleOwnerLiveData.observeForever { lifeCycleOwner ->
                if (lifeCycleOwner != null) {
                    // The fragment’s view has just been created
                    Navigation.setViewNavController(fragment.requireView(), navController)
                }
            }
        }
    }
}

Then in my YourFragmentTest i can create another method like:

private fun launchMyFragmentScenario(bundle: Bundle?): FragmentScenario<MyFragment> 
    //viewModel factory can be easily injected if you use FragmentFactory
    = TestFragmentUtils.launchFragmentScenario(bundle, MyFragment(viewModelFactory), navController)

and call it before each test starts. (navController param is mocked in @Before method)

like image 103
MatPag Avatar answered Nov 09 '22 21:11

MatPag