FragmentScenario 配置 - 二进制 XML 文件行,使用 espresso 测试时错误膨胀 class <widget>
FragmentScenario configuration - Binary XML file line, Error inflating class <widget> while testing with espresso
如果在 XML 中使用 material 组件,则尝试将 FragmentScenario
与 launchFragment
和 launchFragmentInContainer
一起使用时出现膨胀错误。
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.perform(FragmentScenario.java:308)
at androidx.fragment.app.testing.FragmentScenario.perform(FragmentScenario.java:286)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$ActivityScenario(ActivityScenario.java:534)
at androidx.test.core.app.ActivityScenario$$Lambda[=13=].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 因为缺少样式。
首先一定要有最新的fragment-testing
依赖:
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
一些附加信息:
- 此修复程序已在版本
1.1.0-alpha03
中发布,因此之前的版本将无法像 here 所述那样工作。
- 记得使用
debugImplementation
否则依赖项将无法正常工作,感谢这个 so answer
- 如果您遇到类似
"process crashed, "No tests found.""
的错误,请检查此 issue 是否有帮助。
在此之后您可以创建片段:
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.
在我的例子中,我有 Navigation component configured so I had to follow the suggestion of the official documentation 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)
并在每次测试开始前调用它。 (navController
参数在@Before 方法中被模拟)
如果在 XML 中使用 material 组件,则尝试将 FragmentScenario
与 launchFragment
和 launchFragmentInContainer
一起使用时出现膨胀错误。
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.perform(FragmentScenario.java:308)
at androidx.fragment.app.testing.FragmentScenario.perform(FragmentScenario.java:286)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$ActivityScenario(ActivityScenario.java:534)
at androidx.test.core.app.ActivityScenario$$Lambda[=13=].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 因为缺少样式。
首先一定要有最新的fragment-testing
依赖:
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
一些附加信息:
- 此修复程序已在版本
1.1.0-alpha03
中发布,因此之前的版本将无法像 here 所述那样工作。 - 记得使用
debugImplementation
否则依赖项将无法正常工作,感谢这个 so answer - 如果您遇到类似
"process crashed, "No tests found.""
的错误,请检查此 issue 是否有帮助。
在此之后您可以创建片段:
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 theandroid.view.InflateException
error if you use widgets coming from thecom.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.
在我的例子中,我有 Navigation component configured so I had to follow the suggestion of the official documentation 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)
并在每次测试开始前调用它。 (navController
参数在@Before 方法中被模拟)