如何在对话框片段上运行单元测试?

Sha*_*awn 3 android android-dialog android-dialogfragment android-espresso

我正在尝试为 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")

    }
}

Run Code Online (Sandbox Code Playgroud)

我的测试

@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()))
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,出现以下错误。

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} 
Run Code Online (Sandbox Code Playgroud)

尝试了不同的解决方案。

        scenario.onFragment {
        onView(withText(R.string.resetscore_dialog_message))
            .check(matches(isDisplayed()))
        }
Run Code Online (Sandbox Code Playgroud)

androidx.test.espresso.NoMatchingViewException:层次结构中没有找到匹配的视图:资源 ID 中的字符串:<2131755113>

        onView(withText(R.string.resetscore_dialog_message))
            .inRoot(isDialog())
            .check(matches(isDisplayed()))
Run Code Online (Sandbox Code Playgroud)

androidx.test.espresso.NoMatchingRootException:匹配器“是对话框”与以下任何根都不匹配:[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()))
        }
Run Code Online (Sandbox Code Playgroud)

androidx.test.espresso.NoMatchingRootException:匹配器“是对话框”与以下任何根都不匹配:[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

Mat*_*Pag 5

launchFragmentInContainer测试时不能使用DialogFragment.

切换到launchFragment扩展

在测试类中放置一个类似的函数,并在每次测试之前调用它:

/**
  * Launch YuorDialogFragment dialogfragment
  */
private fun openDialogFragment(): FragmentScenario<YuorDialogFragment> {
  return launchFragment(
    themeResId = R.style.AppTheme
  ) {
    return@launchFragment YuorDialogFragment(
      ViewModelUtil.createFor(mockViewModel)
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

将对话框测试放入androidTest文件夹中

  • 很酷,确实如此,我只需将 `inRooth(isDialog())` 添加到 onView 即可。 (2认同)