सेल्फ़-इंस्ट्रूमेंटिंग टेस्ट का उदाहरण

इंस्ट्रुमेंटेशन टेस्ट शुरू होने पर, उसके टारगेट पैकेज को रीस्टार्ट किया जाता है. साथ ही, उसमें इंस्ट्रुमेंटेशन कोड डाला जाता है और उसे एक्ज़ीक्यूट किया जाता है. हालांकि, यहां टारगेट पैकेज, Android ऐप्लिकेशन फ़्रेमवर्क नहीं हो सकता. जैसे, android पैकेज. ऐसा इसलिए, क्योंकि इससे विरोधाभासी स्थिति पैदा हो सकती है. इसमें Android फ़्रेमवर्क को रीस्टार्ट करना होगा. यह फ़्रेमवर्क, सिस्टम के फ़ंक्शन को सपोर्ट करता है. इनमें इंस्ट्रुमेंटेशन भी शामिल है.

इसका मतलब है कि इंस्ट्रुमेंटेशन टेस्ट, एक्ज़ीक्यूशन के लिए Android फ़्रेमवर्क में खुद को इंजेक्ट नहीं कर सकता. इसे सिस्टम सर्वर भी कहा जाता है. Android फ़्रेमवर्क को टेस्ट करने के लिए, टेस्ट कोड सिर्फ़ सार्वजनिक एपीआई सर्फ़ेस या प्लैटफ़ॉर्म सोर्स ट्री में उपलब्ध Android इंटरफ़ेस डेफ़िनिशन लैंग्वेज एआईडीएल का इस्तेमाल करके दिखाए गए एपीआई को कॉल कर सकता है. इस कैटगरी के टेस्ट के लिए, किसी खास पैकेज को टारगेट करना सही नहीं है. इसलिए, ऐसे इंस्ट्रुमेंटेशन को अपने टेस्ट ऐप्लिकेशन पैकेज को टारगेट करने के लिए, आम तौर पर घोषित किया जाता है. इसे AndroidManifest.xml के <manifest> टैग में तय किया जाता है.

ज़रूरत के हिसाब से, इस कैटगरी में टेस्ट ऐप्लिकेशन पैकेज भी ये काम कर सकते हैं:

  • टेस्टिंग के लिए ज़रूरी गतिविधियां बंडल करना.
  • सिस्टम के साथ उपयोगकर्ता आईडी शेयर करना.
  • प्लैटफ़ॉर्म पासकोड से साइन करना.
  • सार्वजनिक एसडीके के बजाय, फ़्रेमवर्क सोर्स के ख़िलाफ़ कंपाइल करना.

इंस्ट्रुमेंटेशन टेस्ट की इस कैटगरी को कभी-कभी सेल्फ़-इंस्ट्रुमेंटेशन कहा जाता है. प्लैटफ़ॉर्म सोर्स में, सेल्फ़-इंस्ट्रुमेंटेशन टेस्ट के कुछ उदाहरण यहां दिए गए हैं:

यहां दिए गए उदाहरण में, टारगेट पैकेज को अपने टेस्ट ऐप्लिकेशन पैकेज पर सेट करके, नया इंस्ट्रुमेंटेशन टेस्ट लिखा गया है. इस गाइड में, उदाहरण के तौर पर इस टेस्ट का इस्तेमाल किया गया है:

आगे बढ़ने से पहले, कोड को ब्राउज़ करने का सुझाव दिया जाता है, ताकि आपको इसकी सामान्य जानकारी मिल सके.

सोर्स की जगह तय करना

आम तौर पर, आपकी टीम के पास कोड की जांच करने और टेस्ट जोड़ने के लिए, पहले से ही एक पैटर्न होगा. ज़्यादातर टीमों के पास एक ही Git रिपॉज़िटरी होती है या वे दूसरी टीमों के साथ एक रिपॉज़िटरी शेयर करती हैं. हालांकि, उनके पास एक सब-डायरेक्ट्री होती है, जिसमें कॉम्पोनेंट सोर्स कोड होता है.

मान लें कि आपके कॉम्पोनेंट सोर्स की रूट जगह <component source root> पर है. ज़्यादातर कॉम्पोनेंट में इसके तहत src और tests फ़ोल्डर होते हैं. साथ ही, कुछ अतिरिक्त फ़ाइलें भी होती हैं. जैसे, Android.mk (या इसे अतिरिक्त .mk फ़ाइलों में बांटा गया है), मेनिफ़ेस्ट फ़ाइल AndroidManifest.xml, और टेस्ट कॉन्फ़िगरेशन फ़ाइल 'AndroidTest.xml'.

नया टेस्ट जोड़ने के लिए, आपको शायद अपने कॉम्पोनेंट src के बगल में tests डायरेक्ट्री बनानी होगी और उसमें कॉन्टेंट जोड़ना होगा.

कुछ मामलों में, आपकी टीम के पास tests के तहत डायरेक्ट्री के और स्ट्रक्चर हो सकते हैं. ऐसा इसलिए, क्योंकि अलग-अलग टेस्ट सुइट को अलग-अलग APK में पैकेज करने की ज़रूरत होती है. ऐसे में, आपको tests के तहत एक नई सब-डायरेक्ट्री बनानी होगी.

स्ट्रक्चर कैसा भी हो, आपको tests डायरेक्ट्री या नई बनाई गई सब-डायरेक्ट्री में, gerrit में बदलाव के सैंपल में instrumentation डायरेक्ट्री में मौजूद फ़ाइलों जैसी फ़ाइलें जोड़नी होंगी. हर फ़ाइल के बारे में जानकारी, इस दस्तावेज़ में आगे दी गई है.

मेनिफ़ेस्ट फ़ाइल

किसी ऐप्लिकेशन प्रोजेक्ट की तरह, हर इंस्ट्रुमेंटेशन टेस्ट मॉड्यूल के लिए, AndroidManifest.xml नाम की मेनिफ़ेस्ट फ़ाइल की ज़रूरत होती है. BUILD_PACKAGE कोर मेकफ़ाइल का इस्तेमाल करके, इस फ़ाइल को अपने-आप शामिल करने के लिए, इसे अपने टेस्ट मॉड्यूल की Android.mk फ़ाइल के बगल में रखें.

अगर आपको AndroidManifest.xml फ़ाइल के बारे में जानकारी नहीं है, तो ऐप्लिकेशन मेनिफ़ेस्ट की खास जानकारी देखें

AndroidManifest.xml फ़ाइल का एक सैंपल यहां दिया गया है:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

मेनिफ़ेस्ट फ़ाइल के बारे में कुछ चुनिंदा टिप्पणियां:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

package एट्रिब्यूट, ऐप्लिकेशन पैकेज का नाम होता है. यह यूनीक आइडेंटिफ़ायर है, जिसका इस्तेमाल Android ऐप्लिकेशन फ़्रेमवर्क, किसी ऐप्लिकेशन की पहचान करने के लिए करता है. इस संदर्भ में, यह आपके टेस्ट ऐप्लिकेशन की पहचान करने के लिए इस्तेमाल किया जाता है. सिस्टम में हर उपयोगकर्ता, उस पैकेज के नाम वाला सिर्फ़ एक ऐप्लिकेशन इंस्टॉल कर सकता है.

इसके अलावा, यह package एट्रिब्यूट, what ComponentName#getPackageName() से मिलने वाली वैल्यू के बराबर होता है. साथ ही, various pm sub commands का इस्तेमाल करके, adb shell के ज़रिए इंटरैक्ट करने के लिए भी इसका इस्तेमाल किया जाता है.

ध्यान दें कि पैकेज का नाम, आम तौर पर Java पैकेज के नाम के जैसा होता है. हालांकि, इसका Java पैकेज के नाम से बहुत कम लेना-देना होता है. दूसरे शब्दों में कहें, तो आपके ऐप्लिकेशन (या टेस्ट) पैकेज में, किसी भी पैकेज के नाम वाली क्लास शामिल हो सकती हैं. हालांकि, दूसरी ओर, आपके पास आसानी के लिए, अपने ऐप्लिकेशन या टेस्ट में टॉप लेवल Java पैकेज का नाम, ऐप्लिकेशन पैकेज के नाम जैसा रखने का विकल्प होता है.

android:sharedUserId="android.uid.system"

इससे यह पता चलता है कि इंस्टॉल करते समय, इस APK फ़ाइल को कोर प्लैटफ़ॉर्म के जैसा ही उपयोगकर्ता आईडी, यानी रनटाइम आइडेंटिटी दी जानी चाहिए. ध्यान दें कि यह इस बात पर निर्भर करता है कि APK को कोर प्लैटफ़ॉर्म के जैसे ही सर्टिफ़िकेट से साइन किया गया हो. इसके बारे में जानकारी, पिछले सेक्शन में LOCAL_CERTIFICATE में दी गई है. हालांकि, ये अलग-अलग कॉन्सेप्ट हैं:

  • कुछ अनुमतियां या एपीआई, सिग्नेचर से सुरक्षित होते हैं. इसके लिए, एक ही साइनिंग सर्टिफ़िकेट की ज़रूरत होती है
  • कुछ अनुमतियों या एपीआई के लिए, कॉलर की system उपयोगकर्ता आइडेंटिटी की ज़रूरत होती है. इसके लिए, कॉल करने वाले पैकेज को system के साथ उपयोगकर्ता आईडी शेयर करना ज़रूरी है. ऐसा तब करना होता है, जब यह कोर प्लैटफ़ॉर्म से अलग पैकेज हो
<uses-library android:name="android.test.runner" />

यह सभी इंस्ट्रुमेंटेशन टेस्ट के लिए ज़रूरी है, क्योंकि इससे जुड़ी क्लास को अलग फ़्रेमवर्क JAR लाइब्रेरी फ़ाइल में पैकेज किया जाता है. इसलिए, जब टेस्ट पैकेज को ऐप्लिकेशन फ़्रेमवर्क से कॉल किया जाता है, तो इसके लिए अतिरिक्त क्लासपाथ एंट्री की ज़रूरत होती है.

android:targetPackage="android.test.example.helloworld"

आपने शायद देखा होगा कि यहां targetPackage को, इस फ़ाइल के manifest टैग में बताए गए package एट्रिब्यूट के जैसा ही बताया गया है. टेस्टिंग की बुनियादी जानकारी में बताया गया है कि इंस्ट्रुमेंटेशन टेस्ट की इस कैटगरी का इस्तेमाल, आम तौर पर फ़्रेमवर्क एपीआई को टेस्ट करने के लिए किया जाता है. इसलिए, इनके लिए किसी खास टारगेट किए गए ऐप्लिकेशन पैकेज का होना ज़रूरी नहीं है. हालांकि, यह खुद को टारगेट कर सकता है.

आसान कॉन्फ़िगरेशन फ़ाइल

हर नए टेस्ट मॉड्यूल के लिए, एक कॉन्फ़िगरेशन फ़ाइल होनी चाहिए. इससे बिल्ड सिस्टम को मॉड्यूल मेटाडेटा, कंपाइल-टाइम डिपेंडेंसी, और पैकेजिंग के निर्देशों के बारे में जानकारी मिलती है. ज़्यादातर मामलों में, Soong पर आधारित, ब्लूप्रिंट फ़ाइल का विकल्प काफ़ी होता है. ज़्यादा जानकारी के लिए, टेस्ट का आसान कॉन्फ़िगरेशन देखें.

जटिल कॉन्फ़िगरेशन फ़ाइल

ज़्यादा जटिल मामलों के लिए, आपको Android के टेस्ट हार्नेस, Trade Federation के लिए टेस्ट कॉन्फ़िगरेशन फ़ाइल भी लिखनी होगी.

टेस्ट कॉन्फ़िगरेशन में, डिवाइस के खास सेटअप के विकल्प और टेस्ट क्लास को देने के लिए डिफ़ॉल्ट आर्ग्युमेंट तय किए जा सकते हैं. /platform_testing/tests/example/instrumentation/AndroidTest.xml पर मौजूद उदाहरण देखें.

यहां एक स्नैपशॉट शामिल किया गया है, ताकि आपको आसानी हो:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

टेस्ट कॉन्फ़िगरेशन फ़ाइल के बारे में कुछ चुनिंदा टिप्पणियां:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

इससे Trade Federation को, टारगेट डिवाइस पर HelloWorldTests.apk इंस्टॉल करने के लिए कहा जाता है. इसके लिए, तय किया गया target_preparer इस्तेमाल किया जाता है. Trade Federation में, डेवलपर के लिए कई टारगेट प्रिपेरर उपलब्ध हैं. इनका इस्तेमाल करके, यह पक्का किया जा सकता है कि टेस्ट को एक्ज़ीक्यूट करने से पहले, डिवाइस को सही तरीके से सेटअप किया गया हो.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

इससे, टेस्ट को एक्ज़ीक्यूट करने के लिए, Trade Federation की टेस्ट क्लास तय की जाती है. साथ ही, डिवाइस पर एक्ज़ीक्यूट किए जाने वाले पैकेज और टेस्ट रनर फ़्रेमवर्क को पास किया जाता है. इस मामले में, यह JUnit है.

ज़्यादा जानकारी के लिए, टेस्ट मॉड्यूल के कॉन्फ़िगरेशन देखें.

JUnit4 की सुविधाएं

टेस्ट रनर के तौर पर android-support-test लाइब्रेरी का इस्तेमाल करने से, JUnit4 स्टाइल की नई टेस्ट क्लास को अपनाया जा सकता है. साथ ही, gerrit में बदलाव के सैंपल में, इसकी सुविधाओं का बहुत बुनियादी इस्तेमाल शामिल है. /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java पर मौजूद उदाहरण देखें.

टेस्टिंग के पैटर्न, आम तौर पर कॉम्पोनेंट टीमों के हिसाब से अलग-अलग होते हैं. हालांकि, इस्तेमाल के कुछ पैटर्न आम तौर पर काम के होते हैं.

@RunWith(JUnit4.class)
public class HelloWorldTest {

JUnit4 में एक अहम अंतर यह है कि टेस्ट के लिए, अब किसी सामान्य बेस टेस्ट क्लास से इनहेरिट करने की ज़रूरत नहीं होती. इसके बजाय, सामान्य Java क्लास में टेस्ट लिखे जाते हैं और कुछ टेस्ट सेटअप और कंस्ट्रेंट के बारे में बताने के लिए, एनोटेशन का इस्तेमाल किया जाता है. इस उदाहरण में, हम यह निर्देश दे रहे हैं कि इस क्लास को JUnit4 टेस्ट के तौर पर चलाया जाना चाहिए.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

JUnit4 में, @Before और @After एनोटेशन का इस्तेमाल, टेस्ट से पहले सेटअप करने और टेस्ट के बाद सेटअप हटाने के लिए किया जाता है. इसी तरह, JUnit4 में @BeforeClass और @AfterClass एनोटेशन का इस्तेमाल, टेस्ट क्लास में सभी टेस्ट को एक्ज़ीक्यूट करने से पहले सेटअप करने और बाद में सेटअप हटाने के लिए किया जाता है. ध्यान दें कि क्लास-स्कोप सेटअप और सेटअप हटाने के तरीके स्टैटिक होने चाहिए. टेस्ट के तरीकों के लिए, JUnit के पुराने वर्शन के उलट, अब इनके नाम की शुरुआत test से करने की ज़रूरत नहीं है. इसके बजाय, इनमें से हर तरीके को @Test से एनोटेट किया जाना चाहिए. आम तौर पर, टेस्ट के तरीके सार्वजनिक होने चाहिए. इनमें कोई रिटर्न वैल्यू नहीं होनी चाहिए, कोई पैरामीटर नहीं होना चाहिए, और इनमें अपवाद हो सकते हैं.

इंस्ट्रुमेंटेशन क्लास का ऐक्सेस

हालांकि, बुनियादी Hello World के उदाहरण में इसे शामिल नहीं किया गया है, लेकिन Android टेस्ट के लिए, Instrumentation इंस्टेंस का ऐक्सेस होना आम बात है. यह कोर एपीआई इंटरफ़ेस है, जो ऐप्लिकेशन के कॉन्टेक्स्ट, गतिविधि के लाइफ़साइकल से जुड़े टेस्ट एपीआई वगैरह का ऐक्सेस देता है.

JUnit4 टेस्ट के लिए, अब किसी सामान्य बेस क्लास की ज़रूरत नहीं होती. इसलिए, Instrumentation इंस्टेंस पाने की ज़रूरत नहीं है InstrumentationTestCase#getInstrumentation(). इसके बजाय, नया टेस्ट रनर इसे InstrumentationRegistry के ज़रिए मैनेज करता है. इसमें, इंस्ट्रुमेंटेशन फ़्रेमवर्क से बनाया गया कॉन्टेक्चुअल और एनवायरमेंटल सेटअप सेव किया जाता है.

Instrumentation क्लास के इंस्टेंस को ऐक्सेस करने के लिए, InstrumentationRegistry क्लास पर स्टैटिक मेथड getInstrumentation() को कॉल करें:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

स्थानीय तौर पर बिल्ड करना और टेस्ट करना

सबसे सामान्य इस्तेमाल के मामलों के लिए, Atestका इस्तेमाल करें.

ज़्यादा जटिल मामलों के लिए, जिनमें ज़्यादा कस्टमाइज़ेशन की ज़रूरत होती है, इंस्ट्रुमेंटेशन के निर्देश देखें.