किसी ऐप्लिकेशन को टारगेट करने का उदाहरण

इंस्ट्रुमेंटेशन टेस्ट की यह कैटगरी, सामान्य Android ऐप्लिकेशन को टारगेट करने वाले टेस्ट से ज़्यादा अलग नहीं है. ध्यान दें कि जिस ऐप्लिकेशन में इंस्ट्रुमेंटेशन शामिल है उसे उसी सर्टिफ़िकेट से साइन किया जाना चाहिए जिससे टारगेट किए जा रहे ऐप्लिकेशन को साइन किया गया है.

ध्यान दें कि इस गाइड में यह माना गया है कि आपको प्लैटफ़ॉर्म सोर्स ट्री वर्कफ़्लो के बारे में पहले से कुछ जानकारी है. अगर ऐसा नहीं है, तो कृपया ज़रूरी शर्तें देखें. यहां दिए गए उदाहरण में, टारगेट पैकेज के साथ एक नया इंस्ट्रुमेंटेशन टेस्ट लिखा गया है. टारगेट पैकेज को उसके अपने टेस्ट ऐप्लिकेशन पैकेज पर सेट किया गया है. अगर आपको इस कॉन्सेप्ट के बारे में नहीं पता है, तो कृपया प्लैटफ़ॉर्म टेस्टिंग के बारे में जानकारी पढ़ें.

इस गाइड में, फ़ॉलो टेस्ट को एक उदाहरण के तौर पर इस्तेमाल किया गया है:

  • frameworks/base/packages/Shell/tests

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

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

इंस्ट्रुमेंटेशन टेस्ट किसी ऐप्लिकेशन को टारगेट करेगा. इसलिए, टेस्ट के सोर्स कोड को प्लैटफ़ॉर्म सोर्स ट्री में, आपके कॉम्पोनेंट के सोर्स डायरेक्ट्री के रूट में मौजूद tests डायरेक्ट्री में रखा जाता है.

सेल्फ़-इंस्ट्रुमेंटिंग टेस्ट के लिए एंड-टू-एंड उदाहरण में, सोर्स लोकेशन के बारे में ज़्यादा चर्चा देखें.

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

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

आगे बढ़ने से पहले, हमारा सुझाव है कि आप सबसे पहले ऐप्लिकेशन मेनिफ़ेस्ट की खास जानकारी पढ़ें.

इससे मेनिफ़ेस्ट फ़ाइल के बुनियादी कॉम्पोनेंट और उनके काम करने के तरीके के बारे में खास जानकारी मिलती है.

गैरिट में किए गए बदलाव के सैंपल के लिए मेनिफ़ेस्ट फ़ाइल के नए वर्शन को यहां ऐक्सेस किया जा सकता है: https://android.googlesource.com/platform/frameworks/base/+/android16-qpr2-release/packages/Shell/tests/AndroidManifest.xml

आपकी सुविधा के लिए, यहां एक स्नैपशॉट शामिल किया गया है:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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

        <activity
            android:name="com.android.shell.ActionSendMultipleConsumerActivity"
            android:label="ActionSendMultipleConsumer"
            android:theme="@android:style/Theme.NoDisplay"
            android:noHistory="true"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.shell"
        android:label="Tests for Shell" />

</manifest>

मेनिफ़ेस्ट फ़ाइल के बारे में कुछ ज़रूरी बातें:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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

यह एक टेस्ट ऐप्लिकेशन पैकेज है. यह टेस्ट किए जा रहे ऐप्लिकेशन पैकेज से अलग है. इसलिए, पैकेज का कोई दूसरा नाम इस्तेमाल किया जाना चाहिए. एक सामान्य तरीका यह है कि .test सफ़िक्स जोड़ा जाए.

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

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

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

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

android:targetPackage="com.android.shell"

इससे इंस्ट्रुमेंटेशन के टारगेट पैकेज को com.android.shell पर सेट किया जाता है. am instrument कमांड के ज़रिए इंस्ट्रुमेंटेशन शुरू करने पर, फ़्रेमवर्क com.android.shell प्रोसेस को फिर से शुरू करता है. साथ ही, टेस्ट को लागू करने के लिए, प्रोसेस में इंस्ट्रुमेंटेशन कोड डालता है. इसका यह भी मतलब है कि टेस्ट कोड के पास, जांच किए जा रहे ऐप्लिकेशन में चल रहे सभी क्लास इंस्टेंस का ऐक्सेस होगा. साथ ही, यह टेस्ट हुक के आधार पर स्थिति में बदलाव कर सकता है.

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

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

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

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

टेस्ट कॉन्फ़िगरेशन में, डिवाइस सेटअप के खास विकल्प और टेस्ट क्लास को उपलब्ध कराने के लिए डिफ़ॉल्ट आर्ग्युमेंट तय किए जा सकते हैं.

सैंपल gerrit बदलाव के लिए कॉन्फ़िगरेशन फ़ाइल के नए वर्शन को यहां ऐक्सेस किया जा सकता है: frameworks/base/packages/Shell/tests/AndroidTest.xml

आपकी सुविधा के लिए, यहां एक स्नैपशॉट शामिल किया गया है:

<configuration description="Runs Tests for Shell.">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk" />
    </target_preparer>

    <option name="test-suite-tag" value="apct" />
    <option name="test-tag" value="ShellTests" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.shell.tests" />
        <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="ShellTests.apk"/>
</target_preparer>

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

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

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

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

JUnit4 की सुविधाएं

android-support-test लाइब्रेरी को टेस्ट रनर के तौर पर इस्तेमाल करने से, JUnit4 स्टाइल की नई टेस्ट क्लास को अपनाया जा सकता है. साथ ही, सैंपल Gerrit बदलाव में इसकी कुछ बुनियादी सुविधाओं का इस्तेमाल किया गया है.

Gerrit में किए गए बदलाव के सैंपल का नया सोर्स कोड यहां ऐक्सेस किया जा सकता है: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

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

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

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

@SmallTest एनोटेशन ने पूरी टेस्ट क्लास के लिए टेस्ट का साइज़ तय किया है: इस टेस्ट क्लास में जोड़े गए सभी टेस्ट मेथड, टेस्ट के साइज़ वाले इस एनोटेशन को इनहेरिट करते हैं. प्री टेस्ट क्लास सेटअप, पोस्ट टेस्ट टियर डाउन, और पोस्ट टेस्ट क्लास टियर डाउन: JUnit4 में setUp और tearDown तरीकों की तरह. Test एनोटेशन का इस्तेमाल, असल टेस्ट को एनोटेट करने के लिए किया जाता है.

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

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

टेस्ट के तरीकों के लिए, JUnit के पिछले वर्शन के उलट, अब उन्हें test से शुरू करने की ज़रूरत नहीं है. इसके बजाय, हर तरीके को @Test से एनोटेट किया जाना चाहिए. हमेशा की तरह, टेस्ट के तरीके सार्वजनिक होने चाहिए. साथ ही, उनमें कोई रिटर्न वैल्यू नहीं होनी चाहिए, कोई पैरामीटर नहीं होना चाहिए, और वे अपवादों को थ्रो कर सकते हैं.

        Context context = InstrumentationRegistry.getTargetContext();

JUnit4 टेस्ट के लिए अब किसी सामान्य बेस क्लास की ज़रूरत नहीं होती. इसलिए, अब getContext() के ज़रिए Context इंस्टेंस या बेस क्लास के तरीकों के ज़रिए getTargetContext() इंस्टेंस पाना ज़रूरी नहीं है. इसके बजाय, नया टेस्ट रनर उन्हें InstrumentationRegistry के ज़रिए मैनेज करता है. इसमें इंस्ट्रुमेंटेशन फ़्रेमवर्क के ज़रिए बनाया गया कॉन्टेक्स्ट और एनवायरमेंटल सेटअप सेव किया जाता है. इस क्लास के ज़रिए, इन्हें भी कॉल किया जा सकता है:

  • getInstrumentation(): Instrumentation क्लास का इंस्टेंस
  • getArguments(): -e <key> <value> के ज़रिए am instrument को पास किए गए कमांड लाइन आर्ग्युमेंट

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

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

ज़्यादा जटिल मामलों में, अपने हिसाब से बदलाव करने के लिए, इंस्ट्रुमेंटेशन से जुड़े निर्देशों का पालन करें.