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

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

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

इस गाइड में, सैंपल के तौर पर इस टेस्ट का इस्तेमाल किया गया है:

  • frameworks/base/packages/Shell/tests

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

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

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

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

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

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

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

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

सैंपल के तौर पर दिए गए gerrit बदलाव के लिए, मेनिफ़ेस्ट फ़ाइल का नया वर्शन यहां ऐक्सेस किया जा सकता है: https://android.googlesource.com/platform/frameworks/base/+/main/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 पैकेज नाम रखें.

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

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

android:targetPackage="com.android.shell"

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

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

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

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

ज़्यादा मुश्किल टेस्ट के लिए, आपको 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() {
    ...

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

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

        Context context = InstrumentationRegistry.getTargetContext();

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

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

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

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

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