Android
लेखन UI परीक्षण - Android
खोज…
परिचय
इस दस्तावेज़ का फोकस लक्ष्य और तरीके का प्रतिनिधित्व करना है कि एंड्रॉइड यूआई और एकीकरण परीक्षण कैसे लिखें। एस्प्रेसो और यूआईयूटोमेटर Google द्वारा प्रदान किए गए हैं, इसलिए इन उपकरणों और उनके संबंधित रैपर जैसे एपियम, स्पाइडर आदि पर ध्यान केंद्रित किया जाना चाहिए।
वाक्य - विन्यास
- निष्क्रिय संसाधन
- स्ट्रिंग getName () - आइडलिंग रिसोर्स का नाम देता है (जिसका उपयोग लॉगिंग और रजिस्ट्रेशन की बेकरारी के लिए किया जाता है)।
- बूलियन isIdleNow () - यदि संसाधन वर्तमान में निष्क्रिय है तो सही है।
- void registerIdleTransitionCallback (IdlingResource.ResourceCallback callback) - संसाधन के साथ दिए गए IdlingResource.ResourceCallback को पंजीकृत करता है।
टिप्पणियों
न्याय नियम:
जैसा कि आप MockWebServer उदाहरण में देख सकते हैं और ActivityTestRule वे JUnit नियमों की श्रेणी में आते हैं, जो आप को परिभाषित जो तब प्रत्येक परीक्षा के लिए मार डाला जाना चाहिए अपने आप बना सकते हैं अपने व्यवहार @see: https://github.com/junit-team/junit4/ wiki / नियम
Appium
पैरामीटर
चूंकि पैरामीटर में कुछ समस्याएं हैं, जब तक कि दस्तावेज़ बग को हल नहीं किया जाता है:
पैरामीटर | विवरण |
---|---|
कक्षा गतिविधि | कौन सी गतिविधि शुरू करनी है |
initialTouchMode | गतिविधि को प्रारंभ में टच मोड में रखा जाना चाहिए: https://android-developers.blogspot.de/2008/12/touch-mode.html |
launchActivity | सच है अगर गतिविधि को एक बार परीक्षण विधि के अनुसार लॉन्च किया जाना चाहिए। यह पहले के पहले विधि से पहले लॉन्च किया जाएगा, और अंतिम के बाद विधि के बाद समाप्त किया जाएगा। |
मॉकवेबसर उदाहरण
यदि आपकी गतिविधियों, अंशों और UI के लिए कुछ पृष्ठभूमि प्रसंस्करण की आवश्यकता होती है, तो उपयोग करने के लिए एक अच्छी चीज है एक MockWebServer जो एक Android डिवाइस पर स्थानीय चलाता है जो आपके UI के लिए एक बंद और परीक्षण योग्य वातावरण लाता है।
https://github.com/square/okhttp/tree/master/mockwebserver
पहला कदम ग्रेडेल डिपेंडेंसी सहित है:
testCompile 'com.squareup.okhttp3:mockwebserver:(insert latest version)'
अब मॉक सर्वर को चलाने और उपयोग करने के चरण हैं:
- नकली सर्वर ऑब्जेक्ट बनाएँ
- इसे विशिष्ट पते और पोर्ट पर शुरू करें (आमतौर पर लोकलहोस्ट: पोर्टनंबर)
- विशिष्ट अनुरोधों के लिए प्रतिक्रियाएँ
- परीक्षण शुरू करें
यह अच्छी तरह से mockwebserver के github पृष्ठ में समझाया गया है, लेकिन हमारे मामले में हम सभी परीक्षणों के लिए कुछ अच्छा और पुन: प्रयोज्य चाहते हैं, और JUnit नियम अच्छी तरह से यहां आ जाएंगे:
/**
*JUnit rule that starts and stops a mock web server for test runner
*/
public class MockServerRule extends UiThreadTestRule {
private MockWebServer mServer;
public static final int MOCK_WEBSERVER_PORT = 8000;
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
startServer();
try {
base.evaluate();
} finally {
stopServer();
}
}
};
}
/**
* Returns the started web server instance
*
* @return mock server
*/
public MockWebServer server() {
return mServer;
}
public void startServer() throws IOException, NoSuchAlgorithmException {
mServer = new MockWebServer();
try {
mServer(MOCK_WEBSERVER_PORT);
} catch (IOException e) {
throw new IllegalStateException(e,"mock server start issue");
}
}
public void stopServer() {
try {
mServer.shutdown();
} catch (IOException e) {
Timber.e(e, "mock server shutdown error”);
}
}
}
अब मान लेते हैं कि हमारे पास पिछले उदाहरण की तरह ही सटीक गतिविधि है, बस इस मामले में जब हम बटन ऐप को धक्का देते हैं तो उदाहरण के लिए नेटवर्क से कुछ प्राप्त होगा: https://someapi.com/name
यह कुछ टेक्स्ट स्ट्रिंग लौटाएगा जिसे स्नैकबार टेक्स्ट जैसे NAME + टेक्स्ट में टाइप किया जाएगा।
/**
* Testing of the snackbar activity with networking.
**/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SnackbarActivityTest{
//espresso rule which tells which activity to start
@Rule
public final ActivityTestRule<SnackbarActivity> mActivityRule =
new ActivityTestRule<>(SnackbarActivity.class, true, false);
//start mock web server
@Rule
public final MockServerRule mMockServerRule = new MockServerRule();
@Override
public void tearDown() throws Exception {
//same as previous example
}
@Override
public void setUp() throws Exception {
//same as previous example
**//IMPORTANT:** point your application to your mockwebserver endpoint e.g.
MyAppConfig.setEndpointURL("http://localhost:8000");
}
/**
*Test methods should always start with "testXYZ" and it is a good idea to
*name them after the intent what you want to test
**/
@Test
public void testSnackbarIsShown() {
//setup mockweb server
mMockServerRule.server().setDispatcher(getDispatcher());
mActivityRule.launchActivity(null);
//check is our text entry displayed and enter some text to it
String textToType="new snackbar text";
onView(withId(R.id.textEntry)).check(matches(isDisplayed()));
//we check is our snackbar showing text from mock webserver plus the one we typed
onView(withId(R.id.textEntry)).perform(typeText("JazzJackTheRabbit" + textToType));
//click the button to show the snackbar
onView(withId(R.id.shownSnackbarBtn)).perform(click());
//assert that a view with snackbar_id with text which we typed and is displayed
onView(allOf(withId(android.support.design.R.id.snackbar_text),
withText(textToType))) .check(matches(isDisplayed()));
}
/**
*creates a mock web server dispatcher with prerecorded requests and responses
**/
private Dispatcher getDispatcher() {
final Dispatcher dispatcher = new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
if (request.getPath().equals("/name")){
return new MockResponse().setResponseCode(200)
.setBody("JazzJackTheRabbit");
}
throw new IllegalStateException("no mock set up for " + request.getPath());
}
};
return dispatcher;
}
मैं आपको किसी प्रकार के बिल्डर में डिस्पैचर को लपेटने का सुझाव दूंगा ताकि आप आसानी से चेन कर सकें और अपनी स्क्रीन के लिए नई प्रतिक्रियाएं जोड़ सकें। जैसे
return newDispatcherBuilder()
.withSerializedJSONBody("/authenticate", Mocks.getAuthenticationResponse())
.withSerializedJSONBody("/getUserInfo", Mocks.getUserInfo())
.withSerializedJSONBody("/checkNotBot", Mocks.checkNotBot());
IdlingResource
निष्क्रिय संसाधनों की शक्ति कुछ ऐप के प्रसंस्करण (नेटवर्किंग, गणना, एनिमेशन, आदि) का इंतजार करने के लिए sleep()
साथ समाप्त करने के लिए नहीं है sleep()
, जो कि चंचलता लाता है और / या परीक्षणों को आगे बढ़ाता है। आधिकारिक दस्तावेज यहां पाया जा सकता है ।
कार्यान्वयन
IdlingResource
इंटरफ़ेस लागू करते समय आपको तीन चीजें करने की आवश्यकता IdlingResource
है:
-
getName()
- आपके निष्क्रिय संसाधन का नाम लौटाता है। -
isIdleNow()
- जाँचता है कि क्या आपका xyz ऑब्जेक्ट, ऑपरेशन, आदि इस समय निष्क्रिय है। -
registerIdleTransitionCallback
(IdlingResource.ResourceCallback
callback) - एक कॉलबैक प्रदान करता है जिसे आपको तब कॉल करना चाहिए जब आपका ऑब्जेक्ट निष्क्रिय हो जाए।
अब आपको अपना तर्क बनाना चाहिए और निर्धारित करना चाहिए कि आपका ऐप कब निष्क्रिय है और कब नहीं, क्योंकि यह ऐप पर निर्भर है। नीचे आपको एक सरल उदाहरण मिलेगा, बस यह दिखाने के लिए कि यह कैसे काम करता है। ऑनलाइन अन्य उदाहरण हैं, लेकिन विशिष्ट एप कार्यान्वयन विशिष्ट निष्क्रिय संसाधन कार्यान्वयन के लिए लाता है।
टिप्पणियाँ
- Google के कुछ उदाहरण हैं जहां उन्होंने ऐप के कोड में
IdlingResources
डाला है। यह मत करो। उन्होंने संभवतः इसे सिर्फ यह दिखाने के लिए रखा कि वे कैसे काम करते हैं। - अपने कोड को साफ रखना और जिम्मेदारी के एकल सिद्धांत को बनाए रखना आपके ऊपर है!
उदाहरण
हमें बताएं कि आपके पास एक गतिविधि है जो अजीब सामान करती है और टुकड़े को लोड करने के लिए एक लंबा समय लगता है और इस प्रकार आपके एस्प्रेसो परीक्षणों को विफल करने से आपके टुकड़े से संसाधन नहीं मिल पाते हैं (आपको बदलना चाहिए कि आपकी गतिविधि कैसे और कब बनी है इसे गति देने के लिए)। लेकिन किसी भी मामले में इसे सरल रखने के लिए, निम्नलिखित उदाहरण दिखाता है कि इसे कैसा दिखना चाहिए।
हमारे उदाहरण निष्क्रिय संसाधन को दो ऑब्जेक्ट मिलेंगे:
- उस टुकड़े का टैग जो आपको गतिविधि से जुड़ने के लिए खोजने और प्रतीक्षा करने की आवश्यकता है।
- एक FragmentManager वस्तु जिसका उपयोग टुकड़ा खोजने के लिए किया जाता है।
/**
* FragmentIdlingResource - idling resource which waits while Fragment has not been loaded.
*/
public class FragmentIdlingResource implements IdlingResource {
private final FragmentManager mFragmentManager;
private final String mTag;
//resource callback you use when your activity transitions to idle
private volatile ResourceCallback resourceCallback;
public FragmentIdlingResource(FragmentManager fragmentManager, String tag) {
mFragmentManager = fragmentManager;
mTag = tag;
}
@Override
public String getName() {
return FragmentIdlingResource.class.getName() + ":" + mTag;
}
@Override
public boolean isIdleNow() {
//simple check, if your fragment is added, then your app has became idle
boolean idle = (mFragmentManager.findFragmentByTag(mTag) != null);
if (idle) {
//IMPORTANT: make sure you call onTransitionToIdle
resourceCallback.onTransitionToIdle();
}
return idle;
}
@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
}
अब जब आपके पास अपना IdlingResource
लिखा है, तो आपको इसे कहीं सही उपयोग करने की आवश्यकता है?
प्रयोग
आइए हम पूरे टेस्ट क्लास सेटअप को छोड़ दें और केवल यह देखें कि एक टेस्ट केस कैसा दिखेगा:
@Test
public void testSomeFragmentText() {
mActivityTestRule.launchActivity(null);
//creating the idling resource
IdlingResource fragmentLoadedIdlingResource = new FragmentIdlingResource(mActivityTestRule.getActivity().getSupportFragmentManager(), SomeFragmentText.TAG);
//registering the idling resource so espresso waits for it
Espresso.registerIdlingResources(idlingResource1);
onView(withId(R.id.txtHelloWorld)).check(matches(withText(helloWorldText)));
//lets cleanup after ourselves
Espresso.unregisterIdlingResources(fragmentLoadedIdlingResource);
}
JUnit नियम के साथ संयोजन
यह कठिन नहीं है; आप JUnit परीक्षण नियम के रूप में निष्क्रिय संसाधन भी लागू कर सकते हैं। उदाहरण के लिए, हम कहें कि आपके पास कुछ SDK हैं जिनमें वोली शामिल है और आप चाहते हैं कि एस्प्रेसो इसके लिए प्रतीक्षा करें। प्रत्येक परीक्षण मामले से गुजरने या इसे सेटअप में लागू करने के बजाय, आप एक JUnit नियम बना सकते हैं और बस लिख सकते हैं:
@Rule
public final SDKIdlingRule mSdkIdlingRule = new SDKIdlingRule(SDKInstanceHolder.getInstance());
अब चूंकि यह एक उदाहरण है, इसलिए इसे स्वीकार न करें; यहाँ सभी कोड काल्पनिक है और केवल प्रदर्शन प्रयोजनों के लिए उपयोग किया जाता है:
public class SDKIdlingRule implements TestRule {
//idling resource you wrote to check is volley idle or not
private VolleyIdlingResource mVolleyIdlingResource;
//request queue that you need from volley to give it to idling resource
private RequestQueue mRequestQueue;
//when using the rule extract the request queue from your SDK
public SDKIdlingRule(SDKClass sdkClass) {
mRequestQueue = getVolleyRequestQueue(sdkClass);
}
private RequestQueue getVolleyRequestQueue(SDKClass sdkClass) {
return sdkClass.getVolleyRequestQueue();
}
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
//registering idling resource
mVolleyIdlingResource = new VolleyIdlingResource(mRequestQueue);
Espresso.registerIdlingResources(mVolleyIdlingResource);
try {
base.evaluate();
} finally {
if (mVolleyIdlingResource != null) {
//deregister the resource when test finishes
Espresso.unregisterIdlingResources(mVolleyIdlingResource);
}
}
}
};
}
}