问题描述
我的应用程序首选项中有发送反馈。它应该打开一个选择器和一个新的Intent,以发送包含提供的电子邮件地址,主题和文本模板的电子邮件。这部分仅可在模拟器和物理设备上使用:
prefButtonSendFeedback?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
val emailIntent = Intent(Intent.ACTION_SENDTO)
emailIntent.type = "text/plain"
emailIntent.data = Uri.parse("mailto:")
emailIntent.putExtra(Intent.EXTRA_EMAIL,arrayOf(getString(R.string.send_Feedback_email_address)))
emailIntent.putExtra(Intent.EXTRA_SUBJECT,getString(R.string.send_Feedback_email_subject))
emailIntent.putExtra(Intent.EXTRA_TEXT,getString(R.string.send_Feedback_email_content_template))
context?.startActivity(Intent.createChooser(emailIntent,getString(R.string.send_Feedback_intent_name)))
true
}
对于这种情况,我也进行了Espresso测试:
@Test fun clickOnFeedbackActionMenuItem_StartsFeedbackFragment() {
launchFragmentInContainer<SettingsFragment>()
Intents.init()
intending(
hasAction(Intent.ACTION_CHOOSER)
).respondWith(
ActivityResult(Activity.RESULT_OK,null)
)
// Press on Feedback navigation item
onView(withId(androidx.preference.R.id.recycler_view))
.perform(
actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.pref_send_Feedback)),click()
)
)
val emailIntent = allOf(
hasAction(Intent.ACTION_SENDTO),hasData(Uri.parse("mailto:")),hasExtra(Intent.EXTRA_EMAIL,arrayOf(withText(R.string.send_Feedback_email_address))),hasExtra(Intent.EXTRA_SUBJECT,withText(R.string.send_Feedback_email_subject)),hasExtra(Intent.EXTRA_TEXT,withText(R.string.send_Feedback_email_content_template))
)
val expectedIntent = allOf(
hasAction(Intent.ACTION_CHOOSER),hasExtra(equalTo(Intent.EXTRA_INTENT),emailIntent),hasExtra(equalTo(Intent.EXTRA_TITLE),withText(R.string.send_Feedback_intent_name))
)
intended(expectedIntent)
Intents.release()
}
我的问题通常与How to stub Intent.createChooser Intent using Espresso的问题相似
- 使用类似代码中的匹配器时,我会出错:
androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: Wanted to match 1 intents. Actually matched 0 intents.
IntentMatcher: (has action: is "android.intent.action.CHOOSER" and has extras: has bundle with: key: "android.intent.extra.INTENT" value: (has action: is "android.intent.action.SENDTO" and has data: is <mailto:> and has extras: has bundle with: key: is "android.intent.extra.EMAIL" value: is [<with string from resource id: <3134850762>>] and has extras: has bundle with: key: is "android.intent.extra.SUBJECT" value: is <with string from resource id: <2131820702>> and has extras: has bundle with: key: is "android.intent.extra.TEXT" value: is <with string from resource id: <2131820701>>))
Matched intents:[]
Recorded intents:
-Intent { act=android.intent.action.CHOOSER (has extras) } handling packages:[[android]],extras:[Bundle[{android.intent.extra.INTENT=Intent { act=android.intent.action.SENDTO dat=mailto: (has extras) },android.intent.extra.TITLE=Send Feedback:}]])
- 当我只有几个Matchers时,测试呈绿色-添加任何其他失败测试:
val emailIntent = allOf(
hasAction(Intent.ACTION_SENDTO),)
val expectedIntent = allOf(
hasAction(Intent.ACTION_CHOOSER),)
- 我还使用了真断言和调试器
val receivedIntent: Intent = Iterables.getonlyElement(Intents.getIntents())
assertthat(receivedIntent).hasAction(Intent.ACTION_CHOOSER) ### here is a breakpoint
它告诉我,我的意图具有我需要的所有其他内容(主题,地址和文字)-我删除了不必要的值:
receivedIntent =
(...)
mAction = "android.intent.action.CHOOSER"
(..)
mExtras =
mMap =
value[0] =
mAction = "android.intent.action.SENDTO"
mData = "mailto:"
mExtras =
mMap =
value[0] = "App Feedback"
value[1] = "Add here any bugs,issues or ideas about App"
value[2] =
0 = "[email protected]"
value[1] = "Send Feedback:"
我的问题是,我的Matchers有什么问题-对我来说,他们看起来还不错:
此外,我不确定intending()
的工作方式-我假设像在代码中那样使用它,在测试期间不会运行真正的Intent。因此它将不会运行电子邮件客户端。我错了-它可以运行,但是如果没有运行,即使我正在使用Intents.release()
,所有下一个测试也会挂起。
解决方法
因此,一旦我对网络资源进行了更深入的研究,我发现了更复杂的Espresso匹配器:
val expectedIntent = allOf(
hasAction(Intent.ACTION_CHOOSER),hasExtra(
equalTo(Intent.EXTRA_INTENT),allOf(
hasAction(Intent.ACTION_SENDTO),hasData(Uri.parse("mailto:")),hasExtra(
`is`(Intent.EXTRA_TEXT),`is`("Add here any bugs,issues or ideas about App")
),hasExtra(
`is`(Intent.EXTRA_EMAIL),`is`(arrayOf("[email protected]"))
),hasExtra(
`is`(Intent.EXTRA_SUBJECT),`is`("App Feedback")
)
)
),hasExtra(
`is`(Intent.EXTRA_TITLE),`is`("Send Feedback:")
)
)
intended(expectedIntent)
很简单。
我仍然不了解其中的区别,所以如果有人可以向我解释一下...
我不知道,为什么这个可行:
hasExtra(
`is`(Intent.EXTRA_TITLE),`is`("Send Feedback:")
)
而这个不是:
hasExtra(
`is`(Intent.EXTRA_TITLE),withText(R.string.send_feedback_intent_name)
)
,
hasExtra(key: String,value: T)
-> hasEntry(is(key),is(value))
hasExtra(keyMatcher,valueMatcher)
-> BundleMatcher(keyMatcher,valueMatcher)
hasExtras(matcher: Mathcer)
-> 新的 TypeSafeMatcher
-> matcher.matches(intent.getExtras())
我就是这么用的。
intended(FilterMatcher.filter<Intent> { intent ->
//check with intent
})
class FilterMatcher<T> (klass: Class<T>,val filter: (data: T) -> Boolean): TypeSafeMatcher<T>(klass) {
companion object {
inline fun <reified T> filter(noinline filter: (data: T) -> Boolean): Matcher<T> = FilterMatcher(T::class.java,filter) as Matcher<T>
inline fun <reified T: View> filterView(noinline filter: (data: T) -> Boolean): Matcher<View> = FilterMatcher(T::class.java,filter) as Matcher<View>
}
override fun describeTo(description: Description?) {
description?.appendText("with filter");
}
override fun matchesSafely(item: T): Boolean = filter(item)
}
,
我仍然不明白其中的区别,所以如果有人可以向我解释...
withText
是用于 matching TextViews 的 Matcher<View>
- 它专门寻找具有指定字符串资源 ID 的 TextView
。除非您将具有相同资源 ID 的 TextView 推送到您的附加内容中,否则它不会起作用。