इस दस्तावेज़ में अलग-अलग तरह के एस्प्रेसो टेस्ट को सेट अप करने के तरीके के बारे में बताया गया है.
किसी दूसरे व्यू के बगल में मौजूद व्यू को मैच करना
किसी लेआउट में कुछ ऐसे व्यू हो सकते हैं जो खुद में यूनीक न हों. इसके लिए
उदाहरण के लिए, संपर्क सूची में मौजूद 'बार-बार होने वाला कॉल' बटन
R.id
में ऐसा ही टेक्स्ट है. साथ ही, इनकी प्रॉपर्टी अन्य कॉल जैसी ही हैं
बटन पर क्लिक कर सकते हैं.
उदाहरण के लिए, इस गतिविधि में, "7"
टेक्स्ट वाला व्यू कई बार दोहराया जाता है
पंक्तियां:
अक्सर, गैर-यूनीक व्यू को किसी यूनीक लेबल के साथ जोड़ा जाएगा
जैसे, कॉल बटन के बगल में मौजूद संपर्क का नाम. इस मामले में,
अपना चुनाव सटीक बनाने के लिए, hasSibling()
मैचर का इस्तेमाल किया जा सकता है:
onView(allOf(withText("7"), hasSibling(withText("item: 0"))))
.perform(click())
onView(allOf(withText("7"), hasSibling(withText("item: 0"))))
.perform(click());
ऐक्शन बार के अंदर मौजूद व्यू को मैच करें
ActionBarTestActivity
में दो अलग-अलग ऐक्शन बार हैं: सामान्य
कार्रवाई बार और संदर्भ के हिसाब से कार्रवाई बार को बनाया गया है, जो विकल्प मेन्यू से बनाया गया है. दोनों
ऐक्शन बार में एक आइटम हमेशा दिखता है और दो ऐसे आइटम होते हैं जो सिर्फ़
ओवरफ़्लो मेनू में दृश्यमान. जब किसी आइटम पर क्लिक किया जाता है, तो यह TextView को
क्लिक किए गए आइटम का कॉन्टेंट.
दोनों ऐक्शन बार पर दिखने वाले आइकॉन को मैच करना आसान है, जैसा कि दिखाया गया है कोड स्निपेट में:
fun testClickActionBarItem() {
// We make sure the contextual action bar is hidden.
onView(withId(R.id.hide_contextual_action_bar))
.perform(click())
// Click on the icon - we can find it by the r.Id.
onView(withId(R.id.action_save))
.perform(click())
// Verify that we have really clicked on the icon
// by checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Save")))
}
public void testClickActionBarItem() {
// We make sure the contextual action bar is hidden.
onView(withId(R.id.hide_contextual_action_bar))
.perform(click());
// Click on the icon - we can find it by the r.Id.
onView(withId(R.id.action_save))
.perform(click());
// Verify that we have really clicked on the icon
// by checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Save")));
}
कॉन्टेक्स्ट के हिसाब से दिए जाने वाले ऐक्शन बार के लिए, यह कोड एक जैसा दिखता है:
fun testClickActionModeItem() {
// Make sure we show the contextual action bar.
onView(withId(R.id.show_contextual_action_bar))
.perform(click())
// Click on the icon.
onView((withId(R.id.action_lock)))
.perform(click())
// Verify that we have really clicked on the icon
// by checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Lock")))
}
public void testClickActionModeItem() {
// Make sure we show the contextual action bar.
onView(withId(R.id.show_contextual_action_bar))
.perform(click());
// Click on the icon.
onView((withId(R.id.action_lock)))
.perform(click());
// Verify that we have really clicked on the icon
// by checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Lock")));
}
सामान्य कार्रवाई के लिए, ओवरफ़्लो मेन्यू में आइटम पर क्लिक करना थोड़ा मुश्किल होता है क्योंकि कुछ डिवाइसों में हार्डवेयर ओवरफ़्लो मेन्यू बटन होता है, जिससे विकल्प मेन्यू में आइटम ओवरफ़्लो होते हैं और कुछ डिवाइसों का सॉफ़्टवेयर ओवरफ़्लो होता है मेन्यू बटन, जो एक सामान्य ओवरफ़्लो मेन्यू खोलता है. अच्छी बात यह है कि Espresso को हमारे लिए.
सामान्य कार्रवाई बार के लिए:
fun testActionBarOverflow() {
// Make sure we hide the contextual action bar.
onView(withId(R.id.hide_contextual_action_bar))
.perform(click())
// Open the options menu OR open the overflow menu, depending on whether
// the device has a hardware or software overflow menu button.
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext<Context>())
// Click the item.
onView(withText("World"))
.perform(click())
// Verify that we have really clicked on the icon by checking
// the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("World")))
}
public void testActionBarOverflow() {
// Make sure we hide the contextual action bar.
onView(withId(R.id.hide_contextual_action_bar))
.perform(click());
// Open the options menu OR open the overflow menu, depending on whether
// the device has a hardware or software overflow menu button.
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext());
// Click the item.
onView(withText("World"))
.perform(click());
// Verify that we have really clicked on the icon by checking
// the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("World")));
}
हार्डवेयर ओवरफ़्लो मेन्यू बटन वाले डिवाइसों पर यह इस तरह दिखता है:
संदर्भ के हिसाब से कार्रवाई बार के लिए, ये काम करना आसान हो गया है:
fun testActionModeOverflow() {
// Show the contextual action bar.
onView(withId(R.id.show_contextual_action_bar))
.perform(click())
// Open the overflow menu from contextual action mode.
openContextualActionModeOverflowMenu()
// Click on the item.
onView(withText("Key"))
.perform(click())
// Verify that we have really clicked on the icon by
// checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Key")))
}
}
public void testActionModeOverflow() {
// Show the contextual action bar.
onView(withId(R.id.show_contextual_action_bar))
.perform(click());
// Open the overflow menu from contextual action mode.
openContextualActionModeOverflowMenu();
// Click on the item.
onView(withText("Key"))
.perform(click());
// Verify that we have really clicked on the icon by
// checking the TextView content.
onView(withId(R.id.text_action_bar_result))
.check(matches(withText("Key")));
}
}
इन सैंपल का पूरा कोड देखने के लिए,
GitHub पर ActionBarTest.java
सैंपल.
दावा करें कि व्यू नहीं दिख रहा है
कार्रवाइयां करने के बाद, आपको
की जांच की जा रही है. कभी-कभी, यह एक नकारात्मक मामला हो सकता है, जैसे कि
कुछ नहीं हो रहा है. ध्यान रखें कि आप किसी भी हैमक्रेस्ट व्यू को पलट सकते हैं
ViewAssertions.matches()
का इस्तेमाल करके ViewAssertion
में 'मैचर' जोड़ा है.
नीचे दिए गए उदाहरण में, हम isDisplayed()
मैचर को लेते हैं और इसका इस्तेमाल करके इसे उलट देते हैं
स्टैंडर्ड not()
मैचर:
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import org.hamcrest.Matchers.not
onView(withId(R.id.bottom_left))
.check(matches(not(isDisplayed())))
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.not;
onView(withId(R.id.bottom_left))
.check(matches(not(isDisplayed())));
ऊपर दिया गया तरीका तब काम करता है, जब व्यू अब भी क्रम में हो. अगर ऐसा है
नहीं, तो आपको एक NoMatchingViewException
मिलेगा और आपको
ViewAssertions.doesNotExist()
.
दावा करें कि व्यू मौजूद नहीं है
अगर व्यू, व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) से हट गया है, तो ऐसा तब हो सकता है, जब
कार्रवाई की वजह से अन्य गतिविधि में बदलाव हुआ—आपको इसका इस्तेमाल करना चाहिए
ViewAssertions.doesNotExist()
:
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers.withId
onView(withId(R.id.bottom_left))
.check(doesNotExist())
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
onView(withId(R.id.bottom_left))
.check(doesNotExist());
पुष्टि करें कि डेटा आइटम, अडैप्टर में नहीं है
यह साबित करने के लिए कि कोई खास डेटा आइटम, AdapterView
में मौजूद नहीं है, आपको ऐसा करना होगा
चीज़ों को थोड़ा अलग तरीके से. हमें जिस AdapterView
में दिलचस्पी है उसे ढूंढना होगा
उसके होल्डिंग डेटा को खोजें और उसके बारे में पूछताछ करें. हमें onData()
का इस्तेमाल करने की ज़रूरत नहीं है.
इसके बजाय, हम AdapterView
को ढूंढने के लिए onView()
का इस्तेमाल करते हैं. इसके बाद, हम दूसरा
मैचर की सुविधा का इस्तेमाल करके व्यू के अंदर के डेटा पर काम कर सकते हैं.
पहला मैचर:
private fun withAdaptedData(dataMatcher: Matcher<Any>): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("with class name: ")
dataMatcher.describeTo(description)
}
public override fun matchesSafely(view: View) : Boolean {
if (view !is AdapterView<*>) {
return false
}
val adapter = view.adapter
for (i in 0 until adapter.count) {
if (dataMatcher.matches(adapter.getItem(i))) {
return true
}
}
return false
}
}
}
private static Matcher<View> withAdaptedData(final Matcher<Object> dataMatcher) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("with class name: ");
dataMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
if (!(view instanceof AdapterView)) {
return false;
}
@SuppressWarnings("rawtypes")
Adapter adapter = ((AdapterView) view).getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
if (dataMatcher.matches(adapter.getItem(i))) {
return true;
}
}
return false;
}
};
}
इसके बाद, AdapterView
को ढूंढने के लिए हमें बस onView()
की ज़रूरत है:
fun testDataItemNotInAdapter() {
onView(withId(R.id.list))
.check(matches(not(withAdaptedData(withItemContent("item: 168")))))
}
}
@SuppressWarnings("unchecked")
public void testDataItemNotInAdapter() {
onView(withId(R.id.list))
.check(matches(not(withAdaptedData(withItemContent("item: 168")))));
}
}
और हमारा एक दावा है, जो "आइटम: 168" के बराबर वाले आइटम पर लागू नहीं होगा यह आईडी सूची के साथ अडैप्टर व्यू में मौजूद होता है.
पूरा सैंपल देखने के लिए, यहां दिए गए सैंपल में testDataItemNotInAdapter()
तरीका देखें
AdapterViewTest.java
GitHub पर क्लास.
कस्टम फ़ेलियर हैंडलर का इस्तेमाल करें
Espresso में डिफ़ॉल्ट FailureHandler
को अपनी पसंद के मुताबिक सेट करने के बाद, यह अनुमति मिल जाती है
अन्य या अलग-अलग तरह की गड़बड़ियों को ठीक करना, जैसे कि स्क्रीनशॉट लेना या पास करना
साथ ही, डीबग करने की ज़्यादा जानकारी दे सकते हैं.
CustomFailureHandlerTest
के उदाहरण में, कस्टम पैरामीटर को लागू करने का तरीका बताया गया है
फ़ेलियर हैंडलर:
private class CustomFailureHandler(targetContext: Context) : FailureHandler {
private val delegate: FailureHandler
init {
delegate = DefaultFailureHandler(targetContext)
}
override fun handle(error: Throwable, viewMatcher: Matcher<View>) {
try {
delegate.handle(error, viewMatcher)
} catch (e: NoMatchingViewException) {
throw MySpecialException(e)
}
}
}
private static class CustomFailureHandler implements FailureHandler {
private final FailureHandler delegate;
public CustomFailureHandler(Context targetContext) {
delegate = new DefaultFailureHandler(targetContext);
}
@Override
public void handle(Throwable error, Matcher<View> viewMatcher) {
try {
delegate.handle(error, viewMatcher);
} catch (NoMatchingViewException e) {
throw new MySpecialException(e);
}
}
}
यह फ़ेलियर हैंडलर के बजाय MySpecialException
NoMatchingViewException
और अन्य सभी विफलताओं को डेलिगेट करता है
DefaultFailureHandler
. CustomFailureHandler
को इनसे रजिस्टर किया जा सकता है
टेस्ट के setUp()
तरीके में एस्प्रेसो:
@Throws(Exception::class)
override fun setUp() {
super.setUp()
getActivity()
setFailureHandler(CustomFailureHandler(
ApplicationProvider.getApplicationContext<Context>()))
}
@Override
public void setUp() throws Exception {
super.setUp();
getActivity();
setFailureHandler(new CustomFailureHandler(
ApplicationProvider.getApplicationContext()));
}
ज़्यादा जानकारी के लिए, देखें
FailureHandler
इंटरफ़ेस और
Espresso.setFailureHandler()
.
उन विंडो को टारगेट करें जो डिफ़ॉल्ट के तौर पर सेट नहीं हैं
Android में कई विंडो काम करती हैं. आम तौर पर, यह जानकारी उपयोगकर्ताओं को दी जाती है
और फिर भी कुछ मामलों में कई विंडो दिखती हैं, जैसे कि
जैसे कि जब आपके इनबॉक्स में एक ऑटो-कंपलीट विंडो मुख्य ऐप्लिकेशन विंडो पर खींची जाती है
खोज विजेट. चीज़ों को आसान बनाने के लिए, Espresso डिफ़ॉल्ट रूप से
बताएं कि आपको किस Window
से इंटरैक्ट करना है. यह अनुमान करीब-करीब
हमेशा अच्छा होता है; हालांकि, बहुत कम मामलों में आपको यह बताना होगा कि
को किसी इंटरैक्शन को लक्षित करना चाहिए. ऐसा करने के लिए, अपनी रूट विंडो उपलब्ध कराई जा सकती है
मैचर या Root
मैचर:
onView(withText("South China Sea"))
.inRoot(withDecorView(not(`is`(getActivity().getWindow().getDecorView()))))
.perform(click())
onView(withText("South China Sea"))
.inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView()))))
.perform(click());
जैसा कि यहां पर किया जा रहा है
ViewMatchers
,
हम पहले से दिया हुआ एक सेट उपलब्ध कराते हैं
RootMatchers
.
बेशक, आप जब चाहें अपना Matcher
ऑब्जेक्ट लागू कर सकते हैं.
MultipleWindowTest पर एक नज़र डालें सैंपल GitHub पर.
सूची की तरह दिखने वाले नतीजों में हेडर या फ़ुटर का मिलान करना
addHeaderView()
का इस्तेमाल करके ListViews
में हेडर और फ़ुटर जोड़े जाते हैं
addFooterView()
तरीके. यह पक्का करने के लिए कि Espresso.onData()
को किस डेटा ऑब्जेक्ट के बारे में पता है
मिलान करने के लिए, पहले से सेट डेटा ऑब्जेक्ट मान को दूसरे पैरामीटर के रूप में पास करना पक्का करें
addHeaderView()
और addFooterView()
के लिए. उदाहरण के लिए:
const val FOOTER = "FOOTER"
...
val footerView = layoutInflater.inflate(R.layout.list_item, listView, false)
footerView.findViewById<TextView>(R.id.item_content).text = "count:"
footerView.findViewById<TextView>(R.id.item_size).text
= data.size.toString
listView.addFooterView(footerView, FOOTER, true)
public static final String FOOTER = "FOOTER";
...
View footerView = layoutInflater.inflate(R.layout.list_item, listView, false);
footerView.findViewById<TextView>(R.id.item_content).setText("count:");
footerView.findViewById<TextView>(R.id.item_size).setText(String.valueOf(data.size()));
listView.addFooterView(footerView, FOOTER, true);
इसके बाद, फ़ुटर के लिए मैचर लिखा जा सकता है:
import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.instanceOf
import org.hamcrest.Matchers.`is`
fun isFooter(): Matcher<Any> {
return allOf(`is`(instanceOf(String::class.java)),
`is`(LongListActivity.FOOTER))
}
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@SuppressWarnings("unchecked")
public static Matcher<Object> isFooter() {
return allOf(is(instanceOf(String.class)), is(LongListActivity.FOOTER));
}
और किसी परीक्षण में दृश्य को लोड करना भी तुंरत है:
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.sample.LongListMatchers.isFooter
fun testClickFooter() {
onData(isFooter())
.perform(click())
// ...
}
import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.sample.LongListMatchers.isFooter;
public void testClickFooter() {
onData(isFooter())
.perform(click());
// ...
}
पूरे कोड सैंपल पर एक नज़र डालें, जो इसकी testClickFooter()
तरीके में मिलेगी
AdapterViewTest.java
GitHub पर.