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

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

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

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

  • जांच के लिए ज़रूरी बंडल गतिविधियां.
  • सिस्टम के साथ User-ID शेयर करें.
  • प्लैटफ़ॉर्म पासकोड से साइन किया गया हो.
  • सार्वजनिक SDK टूल के बजाय, फ़्रेमवर्क सोर्स के हिसाब से कंपाइल किया गया हो.

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

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

हमारा सुझाव है कि आगे बढ़ने से पहले, कोड को ब्राउज़ करके उसका एक अनुमान लगा लें.

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

आम तौर पर, आपकी टीम के पास कोड की जांच करने और जांच करने के लिए जगहों के पैटर्न के बारे में पहले से जानकारी होती है. ज़्यादातर टीमों के पास एक ही 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 एट्रिब्यूट वही है जो ComponentName#getPackageName() दिखाता है. साथ ही, इसका इस्तेमाल adb shell का इस्तेमाल करके, अलग-अलग pm सब-कमांड के साथ इंटरैक्ट करने के लिए किया जाता है.

ध्यान दें कि आम तौर पर, पैकेज का नाम और 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 को, किसी तय target_preparer का इस्तेमाल करके, टारगेट डिवाइस पर HelloWorldTests.apk इंस्टॉल करने के लिए कहा जाता है. 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() {
    ...

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

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

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

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

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

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

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

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

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