FragmentScenario配置-二进制XML文件行,使用espresso测试时膨胀类<widget>时出错

时间:2019-03-19 15:26:13

标签: android android-fragments android-espresso

如果在XML中使用材料组件,则尝试将FragmentScenariolaunchFragmentlaunchFragmentInContainer一起使用时出现膨胀错误。

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)

由于缺少样式,因此无法使XML膨胀。

1 个答案:

答案 0 :(得分:0)

首先请确保具有最新的fragment-testing依赖项:

debugImplementation "androidx.fragment:fragment-testing:1.1.0-alpha05"

一些其他信息:

  1. 该修补程序已发布在1.1.0-alpha03版中,因此以前的版本将无法按here所述进行工作。
  2. 请记住,使用debugImplementation或依赖项将无法正常工作,这要归功于so answer
  3. 如果您遇到类似"process crashed, "No tests found.""的错误,请检查此issue是否可以帮助您。

之后,您可以使用以下内容创建片段:

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

别忘了R.style.Theme_AppCompat,否则Espresso会崩溃   如果您使用来自android.view.InflateException工件的窗口小部件,则会出现com.google.android.material:material错误。显然,如果您需要自定义样式,则可以在styles.xml中添加新规则并在此处引用。

在我的情况下,我配置了Navigation component,因此必须遵循官方文档here的建议,以确保navController在生命周期中正常运行。

首先,我在 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)
                }
            }
        }
    }
}

然后在我的YourFragmentTest中,我可以创建另一种方法,例如:

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

,并在每次测试开始之前调用它。 (在{Before方法中模拟了navController参数)