android - 如何使用 espresso 在 `launchFragment` 范围内测试 android 上的对话框按钮?
问题描述
问题描述
我需要测试对话框中存在的 2 个按钮是否正在执行该dismiss
功能。为此,我正在使用该launchFragment
函数,如文档中所述:
package com.example.myapp.dialog.acr
import androidx.fragment.app.testing.launchFragment
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.example.myapp.R
import com.example.myapp.customViews.ACRProDialog
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class AcrProDialogTest {
@Test
fun closeButtonDismiss() = checkDismissOnClick(R.id.close_button)
@Test
fun notNowButtonDismiss() = checkDismissOnClick(R.id.not_now_button)
private fun checkDismissOnClick(clickViewId: Int) {
with(launchFragment<ACRProDialog>()) {
onFragment { fragment ->
assertThat(fragment.dialog).isNotNull()
assertThat(fragment.requireDialog().isShowing).isTrue()
onView(withId(clickViewId)).perform(click())
fragment.parentFragmentManager.executePendingTransactions()
onView(withId(clickViewId)).check(doesNotExist())
}
}
}
}
问题是这样,测试需要大约 1 分钟才能运行并失败。Express
显然它在通话中“卡住”了
onView(withId(clickViewId)).perform(click())
我想这是由于范围以FragmentScenario
某种方式阻止Espresso
了正确执行其操作。
对话框本身很好,因为如果我在测试环境之外运行应用程序,它可以正常工作。
我第一次失败的尝试
我想简单地在FragmentScenario
. 如下所示:
package com.example.myapp.dialog.acr
import androidx.fragment.app.testing.launchFragment
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.myapp.R
import com.example.myapp.customViews.ACRProDialog
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class AcrProDialogTest {
@Test
fun closeButtonDismiss() = checkDismissOnClick(R.id.close_button)
@Test
fun notNowButtonDismiss() = checkDismissOnClick(R.id.not_now_button)
private fun checkDismissOnClick(clickViewId: Int) {
launchFragment<ACRProDialog>()
onView(withId(clickViewId))
.perform(click())
.check(doesNotExist())
}
}
事实证明,这种方式的测试并不总是很好。dismiss()
因为在检查之前对话框可能尚未运行.check(doesNotExist())
。我相信这就是为什么 Android 文档建议在 a 的范围内,FragmentScenario
以便我们可以强制执行函数,例如dismiss
usingfragment.parentFragmentManager.executePendingTransactions()
我第二次失败的尝试
我还选择了创建一个lambda
先前在其范围内初始化的替代方案,该范围FragmentScenario
将负责执行fragment.parentFragmentManager.executePendingTransactions()
,如下所述:
package com.example.myapp.dialog.acr
import androidx.fragment.app.testing.launchFragment
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.example.myapp.R
import com.example.myapp.customViews.ACRProDialog
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class AcrProDialogTest {
private lateinit var executePendingTransactions: (() -> Unit)
@Before
fun setUp() {
with(launchFragment<ACRProDialog>()) {
onFragment { fragment ->
assertThat(fragment.dialog).isNotNull()
assertThat(fragment.requireDialog().isShowing).isTrue()
executePendingTransactions =
{ fragment.parentFragmentManager.executePendingTransactions() }
}
}
}
@Test
fun closeButtonDismiss() = checkDismissOnClick(R.id.close_button)
@Test
fun notNowButtonDismiss() = checkDismissOnClick(R.id.not_now_button)
private fun checkDismissOnClick(clickViewId: Int) {
onView(withId(clickViewId)).perform(click())
executePendingTransactions()
onView(withId(clickViewId)).check(doesNotExist())
}
}
问题是这样,我得到一个IllegalStateException
, 因为即使我将ragment.parentFragmentManager.executePendingTransactions()
调用保留在lambda
稍后将执行的 a 中,应用程序也知道该对话框与 none 无关parentFragmentManager
:
java.lang.IllegalStateException: Fragment ACRProDialog{8b3f628} (9ae55769-472c-4cd0-9369-8f1f7fab1b35) not associated with a fragment manager.
at androidx.fragment.app.Fragment.getParentFragmentManager(Fragment.java:1040)
at com.example.myapp.dialog.acr.AcrProDialogTest$setUp$1$1$1.invoke(AcrProDialogTest.kt:28)
at com.example.myapp.dialog.acr.AcrProDialogTest$setUp$1$1$1.invoke(AcrProDialogTest.kt:28)
at com.example.myapp.dialog.acr.AcrProDialogTest.checkDismissOnClick(AcrProDialogTest.kt:41)
at com.example.myapp.dialog.acr.AcrProDialogTest.notNowButtonDismiss(AcrProDialogTest.kt:37)
我的对话代码
我想这不相关(因为对话框在非测试环境中正常执行其功能),但我的对话框代码在这里:
...
class ACRProDialog : DialogFragment() {
private lateinit var binding: AcrProDialogBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = AcrProDialogBinding.inflate(LayoutInflater.from(context), container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply {
closeButton.setOnClickListener {
dismiss()
}
testProButton.setOnClickListener {
context?.let {
BannerPatrocineManager(
context = it,
container = null,
type = BannerPatrocineManager.Type.BANNER_INTERSTITIAL,
originBannerInterstitial = PurchaseOrigin.ACR_POPUP
).load()
}
}
notNowButton.setOnClickListener {
dismiss()
}
}
dialog?.setCanceledOnTouchOutside(true)
}
override fun onStart() {
super.onStart()
(view?.parent as View).setBackgroundColor(Color.TRANSPARENT)
}
}
解决方案
推荐阅读
- django - 为什么主管 gunicorn 显示未找到致命错误命令?
- c++ - #pragma pack(1) 导致分段错误
- terraform - 如何确保资源在 terraform 中某些模块中的资源之前被销毁?
- java - 无法使用动态多态性访问方法 [JAVA]
- web-services - 安全的网络服务方法
- firebase - 如何显示 Firebase 存储 img
- c - C - ssprintf() 无法从字符串中检索子字符串
- python - ValueError:我的程序中 int() 的无效文字以及 except 中的 if 语句
- javascript - 将子图像附加到表格顶部
- sql - 如何汇总多次访问我的商店的用户数量