如何 运行 对 Dialog 片段进行单元测试?
How to run a unit test on a Dialog fragment?
我正在尝试为 DialogFragment 创建一个独立的单元测试,因此可以单独测试 DialogFragment。我正在使用 FragmentScenario 来启动 DialogFragment,现在我正在尝试确认是否显示了对话框消息,但最终我将测试按钮点击。
class ResetScoreDialog (val viewModel: MyViewModel) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
// Use the Builder class for convenient dialog construction
val builder = AlertDialog.Builder(it)
builder.setMessage(getString(R.string.resetscore_dialog_message))
.setPositiveButton(getString(R.string.confirm),
DialogInterface.OnClickListener { dialog, id ->
viewModel.resetScore()
})
// Create the AlertDialog object and return it
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}
我的测试
@RunWith(RobolectricTestRunner::class)
class ResetScoreDialogTest {
private lateinit var scenario: FragmentScenario<ResetScoreDialog>
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
viewModel = mock (MyViewModel::class.java)
scenario = launchFragmentInContainer(
factory = MainFragmentFactory(viewModel),
fragmentArgs = null,
themeResId = R.style.Theme_TDDScoreKeeper
)
}
@Test
fun `Dialog Displayed`() {
onView(withText(R.string.resetscore_dialog_message))
.check(matches(isDisplayed()))
}
}
当我 运行 测试时出现以下错误。
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with string from resource id: <2131755113>
View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@4ed1c9d4, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-->ViewStub{id=16908682, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@5853ff65, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+-->FrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@188c12d2, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=0}
尝试了不同的解决方案。
scenario.onFragment {
onView(withText(R.string.resetscore_dialog_message))
.check(matches(isDisplayed()))
}
androidx.test.espresso.NoMatchingViewException:层次结构中未找到匹配的视图:资源 ID 中的字符串:<2131755113>
onView(withText(R.string.resetscore_dialog_message))
.inRoot(isDialog())
.check(matches(isDisplayed()))
androidx.test.espresso.NoMatchingRootException:匹配器 'is dialog' 不匹配以下任何根:[Root{application-window-token=android.view.ViewRootImpl$W@b421ae4, window-token=android.view.ViewRootImpl$W@b421ae4, has-window-focus=true, layout-params-type=1, layout-params-string={(0,0)( fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
scenario.onFragment {
onView(withText(R.string.resetscore_dialog_message))
.inRoot(isDialog())
.check(matches(isDisplayed()))
}
androidx.test.espresso.NoMatchingRootException:匹配器 'is dialog' 不匹配以下任何根:[Root{application-window-token=android.view.ViewRootImpl$W@65799e3f, window-token=android.view.ViewRootImpl$W@65799e3f, has-window-focus=true, layout-params-type=1, layout-params-string={(0,0)( fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
测试 DialogFragment
时不能使用 launchFragmentInContainer
。
切换到 launchFragment
扩展程序
在你的测试中加入一个类似的函数class并在每次测试前调用它:
/**
* Launch YuorDialogFragment dialogfragment
*/
private fun openDialogFragment(): FragmentScenario<YuorDialogFragment> {
return launchFragment(
themeResId = R.style.AppTheme
) {
return@launchFragment YuorDialogFragment(
ViewModelUtil.createFor(mockViewModel)
);
}
}
将对话框测试放入 androidTest
文件夹
我正在尝试为 DialogFragment 创建一个独立的单元测试,因此可以单独测试 DialogFragment。我正在使用 FragmentScenario 来启动 DialogFragment,现在我正在尝试确认是否显示了对话框消息,但最终我将测试按钮点击。
class ResetScoreDialog (val viewModel: MyViewModel) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
// Use the Builder class for convenient dialog construction
val builder = AlertDialog.Builder(it)
builder.setMessage(getString(R.string.resetscore_dialog_message))
.setPositiveButton(getString(R.string.confirm),
DialogInterface.OnClickListener { dialog, id ->
viewModel.resetScore()
})
// Create the AlertDialog object and return it
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}
我的测试
@RunWith(RobolectricTestRunner::class)
class ResetScoreDialogTest {
private lateinit var scenario: FragmentScenario<ResetScoreDialog>
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
viewModel = mock (MyViewModel::class.java)
scenario = launchFragmentInContainer(
factory = MainFragmentFactory(viewModel),
fragmentArgs = null,
themeResId = R.style.Theme_TDDScoreKeeper
)
}
@Test
fun `Dialog Displayed`() {
onView(withText(R.string.resetscore_dialog_message))
.check(matches(isDisplayed()))
}
}
当我 运行 测试时出现以下错误。
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with string from resource id: <2131755113>
View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@4ed1c9d4, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-->ViewStub{id=16908682, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@5853ff65, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+-->FrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=320, height=470, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@188c12d2, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=0}
尝试了不同的解决方案。
scenario.onFragment {
onView(withText(R.string.resetscore_dialog_message))
.check(matches(isDisplayed()))
}
androidx.test.espresso.NoMatchingViewException:层次结构中未找到匹配的视图:资源 ID 中的字符串:<2131755113>
onView(withText(R.string.resetscore_dialog_message))
.inRoot(isDialog())
.check(matches(isDisplayed()))
androidx.test.espresso.NoMatchingRootException:匹配器 'is dialog' 不匹配以下任何根:[Root{application-window-token=android.view.ViewRootImpl$W@b421ae4, window-token=android.view.ViewRootImpl$W@b421ae4, has-window-focus=true, layout-params-type=1, layout-params-string={(0,0)( fillxfill) ty=BASE_APPLICATION wanim=0x10302f8 fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
scenario.onFragment {
onView(withText(R.string.resetscore_dialog_message))
.inRoot(isDialog())
.check(matches(isDisplayed()))
}
androidx.test.espresso.NoMatchingRootException:匹配器 'is dialog' 不匹配以下任何根:[Root{application-window-token=android.view.ViewRootImpl$W@65799e3f, window-token=android.view.ViewRootImpl$W@65799e3f, has-window-focus=true, layout-params-type=1, layout-params-string={(0,0)( fillxfill) ty=BASE_APPLICATION wanim=0x10302f8 fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
测试 DialogFragment
时不能使用 launchFragmentInContainer
。
切换到 launchFragment
扩展程序
在你的测试中加入一个类似的函数class并在每次测试前调用它:
/**
* Launch YuorDialogFragment dialogfragment
*/
private fun openDialogFragment(): FragmentScenario<YuorDialogFragment> {
return launchFragment(
themeResId = R.style.AppTheme
) {
return@launchFragment YuorDialogFragment(
ViewModelUtil.createFor(mockViewModel)
);
}
}
将对话框测试放入 androidTest
文件夹