लोकल यूनिट टेस्ट तैयार करें

लोकल टेस्ट, सीधे आपके वर्कस्टेशन पर चलता है. इसके लिए, Android डिवाइस या एम्युलेटर की ज़रूरत नहीं होती. इसलिए, यह टेस्ट चलाने के लिए Android डिवाइस के बजाय, आपके लोकल Java वर्चुअल मशीन (जेवीएम) का इस्तेमाल करता है. लोकल टेस्ट की मदद से, अपने ऐप्लिकेशन के लॉजिक का आकलन ज़्यादा तेज़ी से किया जा सकता है. हालांकि, Android फ़्रेमवर्क के साथ इंटरैक्ट न कर पाने की वजह से, कुछ ही तरह के टेस्ट चलाए जा सकते हैं.

यूनिट टेस्ट, कोड के एक छोटे सेक्शन के काम करने के तरीके की पुष्टि करता है. इस सेक्शन को टेस्ट की जा रही यूनिट कहा जाता है. इसके लिए, वह कोड को एक्ज़ीक्यूट करता है और नतीजे की जांच करता है.

यूनिट टेस्ट आम तौर पर आसान होते हैं. हालांकि, अगर टेस्ट की जा रही यूनिट को टेस्ट करने के लिए डिज़ाइन नहीं किया गया है, तो उनका सेटअप मुश्किल हो सकता है:

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

Android में यूनिट टेस्टिंग की सामान्य रणनीतियों के बारे में जानने के लिए, क्या टेस्ट करना है लेख पढ़ें.

स्थानीय टेस्ट की जगह

डिफ़ॉल्ट रूप से, लोकल यूनिट टेस्ट के लिए सोर्स फ़ाइलें module-name/src/test/ में रखी जाती हैं. Android Studio का इस्तेमाल करके नया प्रोजेक्ट बनाने पर, यह डायरेक्ट्री पहले से मौजूद होती है.

टेस्टिंग डिपेंडेंसी जोड़ना

आपको अपने प्रोजेक्ट के लिए टेस्टिंग डिपेंडेंसी भी कॉन्फ़िगर करनी होंगी, ताकि JUnit टेस्टिंग फ़्रेमवर्क से मिले स्टैंडर्ड एपीआई का इस्तेमाल किया जा सके.

इसके लिए, अपने ऐप्लिकेशन के मॉड्यूल की build.gradle फ़ाइल खोलें और इन लाइब्रेरी को डिपेंडेंसी के तौर पर तय करें. testImplementation फ़ंक्शन का इस्तेमाल करके बताएं कि ये ऐप्लिकेशन के बजाय, लोकल टेस्ट सोर्स सेट पर लागू होते हैं:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

लोकल यूनिट टेस्ट क्लास बनाना

लोकल यूनिट टेस्ट क्लास को JUnit 4 टेस्ट क्लास के तौर पर लिखा जाता है.

इसके लिए, एक ऐसी क्लास बनाएं जिसमें एक या उससे ज़्यादा टेस्ट मेथड हों. आम तौर पर, ये मेथड module-name/src/test/ में होते हैं. टेस्ट मेथड, @Test एनोटेशन से शुरू होता है. इसमें उस कॉम्पोनेंट के किसी एक पहलू को टेस्ट करने और उसकी पुष्टि करने के लिए कोड होता है जिसे आपको टेस्ट करना है.

यहां दिए गए उदाहरण में, लोकल यूनिट टेस्ट क्लास को लागू करने का तरीका बताया गया है. टेस्ट करने का तरीका emailValidator_correctEmailSimple_returnsTrue(), isValidEmail() की पुष्टि करने की कोशिश करता है. यह ऐप्लिकेशन में मौजूद एक तरीका है. अगर isValidEmail() भी true दिखाता है, तो टेस्ट फ़ंक्शन true दिखाएगा.

Kotlin

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

आपको ऐसे टेस्ट बनाने चाहिए जिन्हें आसानी से पढ़ा जा सके. इनसे यह पता चलता है कि आपके ऐप्लिकेशन के कॉम्पोनेंट, उम्मीद के मुताबिक नतीजे देते हैं या नहीं. हमारा सुझाव है कि आप junit.Assert, Hamcrest या Truth जैसी असर्शन लाइब्रेरी का इस्तेमाल करें. ऊपर दिया गया स्निपेट, junit.Assert को इस्तेमाल करने का एक उदाहरण है.

मॉक की जा सकने वाली Android लाइब्रेरी

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

इससे Android फ़्रेमवर्क में Context जैसी क्लास का रेफ़रंस देते समय, लोकल टेस्ट बनाए जा सकते हैं. सबसे अहम बात यह है कि इसकी मदद से, Android क्लास के साथ मॉकिंग फ़्रेमवर्क का इस्तेमाल किया जा सकता है.

Android डिपेंडेंसी का मॉकअप तैयार करना

एक आम समस्या यह है कि कोई क्लास, स्ट्रिंग रिसॉर्स का इस्तेमाल कर रही है. Context क्लास में getString() तरीके को कॉल करके, स्ट्रिंग रिसॉर्स हासिल किए जा सकते हैं. हालांकि, लोकल टेस्ट में Context या इसके किसी भी तरीके का इस्तेमाल नहीं किया जा सकता, क्योंकि ये Android फ़्रेमवर्क से जुड़े होते हैं. आम तौर पर, getString() को कॉल करने की प्रोसेस को क्लास से बाहर ले जाया जाता है. हालांकि, ऐसा करना हमेशा मुमकिन नहीं होता. इसका समाधान यह है कि Context का एक मॉक या स्टब बनाएं, जो getString() तरीके को शुरू करने पर हमेशा एक ही वैल्यू दिखाए.

Mockable Android लाइब्रेरी और Mockito या MockK जैसे मॉकिंग फ़्रेमवर्क की मदद से, यूनिट टेस्ट में Android क्लास के मॉक के व्यवहार को प्रोग्राम किया जा सकता है.

Mockito का इस्तेमाल करके, अपने लोकल यूनिट टेस्ट में मॉक ऑब्जेक्ट जोड़ने के लिए, इस प्रोग्रामिंग मॉडल का इस्तेमाल करें:

  1. अपनी build.gradle फ़ाइल में Mockito लाइब्रेरी की डिपेंडेंसी शामिल करें. इसके बारे में अपना टेस्टिंग एनवायरमेंट सेट अप करना लेख में बताया गया है.
  2. अपनी यूनिट टेस्ट क्लास की डेफ़िनिशन की शुरुआत में, @RunWith(MockitoJUnitRunner.class) एनोटेशन जोड़ें. यह एनोटेशन, Mockito टेस्ट रनर को यह पुष्टि करने के लिए कहता है कि फ़्रेमवर्क का इस्तेमाल सही तरीके से किया जा रहा है. साथ ही, यह आपके मॉक ऑब्जेक्ट को शुरू करने की प्रोसेस को आसान बनाता है.
  3. Android डिपेंडेंसी के लिए मॉक ऑब्जेक्ट बनाने के लिए, फ़ील्ड के एलान से पहले @Mock एनोटेशन जोड़ें.
  4. डिपेंडेंसी के व्यवहार को स्टब करने के लिए, कोई शर्त तय की जा सकती है. साथ ही, शर्त पूरी होने पर वैल्यू को रिटर्न किया जा सकता है. इसके लिए, when() और thenReturn() तरीकों का इस्तेमाल करें.

यहां दिए गए उदाहरण में, Kotlin में Mockito-Kotlin की मदद से बनाए गए मॉक Context ऑब्जेक्ट का इस्तेमाल करके, यूनिट टेस्ट बनाने का तरीका बताया गया है.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

Mockito फ़्रेमवर्क को इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, Mockito API का रेफ़रंस और सैंपल कोड में SharedPreferencesHelperTest क्लास देखें. Android टेस्टिंग कोडलैब भी आज़माएं.

गड़बड़ी: "Method ... not mocked"

अगर मॉक की जा सकने वाली Android लाइब्रेरी के किसी तरीके को ऐक्सेस करने की कोशिश की जाती है, तो वह Error: "Method ... not mocked मैसेज के साथ एक अपवाद दिखाती है.

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

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }