स्पॉक के साथ कोटलिन में परीक्षण

लेख का उद्देश्य यह दिखाना है कि कोटलिन के साथ स्पॉक का उपयोग करते समय क्या कठिनाइयां आती हैं, उन्हें हल करने के तरीके क्या हैं और इस सवाल का जवाब दें कि क्या आप कोटलिन पर विकसित होने पर स्पॉक का उपयोग करने के लायक है। कट के तहत विवरण।

मैं एक कंपनी के लिए काम करता हूं जो चरम प्रोग्रामिंग का अभ्यास करती है । चरम प्रोग्रामिंग के मुख्य तरीकों में से एक जो हम अपने दैनिक कार्य में उपयोग करते हैं वह टीडीडी (परीक्षण-संचालित विकास) है। इसका मतलब है कि कोड को बदलने से पहले, हम एक परीक्षण लिखते हैं जो वांछित परिवर्तन को कवर करता है। इस प्रकार, हम नियमित रूप से परीक्षण लिखते हैं और 100% के करीब परीक्षणों के साथ कोड कवरेज करते हैं। टेस्ट फ्रेमवर्क चुनने के लिए यह कुछ आवश्यकताओं को पूरा करता है: यह सप्ताह में एक बार परीक्षण लिखने के लिए एक चीज है, यह हर दिन ऐसा करने के लिए काफी अन्य है।

हम कोटलिन पर विकसित कर रहे हैं और कुछ बिंदु पर हमने स्पॉक को मुख्य ढांचे के रूप में चुना। उस क्षण के लगभग 6 महीने बीत चुके हैं, उत्साह और नवीनता की भावना बीत गई है, इसलिए लेख एक प्रकार का पूर्वव्यापी है जिसमें मैं आपको यह बताने की कोशिश करूंगा कि इस दौरान हमें किन कठिनाइयों का सामना करना पड़ा और हमने उन्हें कैसे हल किया।

बिल्कुल क्यों बोले?




सबसे पहले, आपको यह पता लगाने की जरूरत है कि कोटलिन को किन रूपरेखाओं का परीक्षण करने की अनुमति है और उनकी तुलना में स्पॉक क्या फायदे देता है।

कोटलिन के फायदों में से एक जावा के साथ इसकी संगतता है, जो आपको परीक्षण के लिए किसी भी जावा फ्रेमवर्क का उपयोग करने की अनुमति देता है, जैसे कि जूनिट , टेस्टएनजी , स्पॉक , आदि। इसी समय, विशेष रूप से कोटलिन जैसे कि स्पेक और कोटेस्ट के लिए रूपरेखा तैयार की गई है । हमने Spock क्यों चुना?

मैं निम्नलिखित फायदों पर प्रकाश डालूंगा:

  • सबसे पहले, ग्रूवी में स्पॉक लिखा जाता है। अच्छा या बुरा - अपने लिए जज। ग्रूवी के बारे में, आप यहां लेख पढ़ सकते हैं ग्रूवी मुझे व्यक्तिगत रूप से लैकोनिक सिंटैक्स, गतिशील टाइपिंग की उपस्थिति, सूचियों के लिए अंतर्निहित सिंटैक्स, नियमित और साहचर्य सरणियों और पूरी तरह से पागल प्रकार के रूपांतरणों के लिए आकर्षित करता है।
  • दूसरे, Spock में पहले से ही एक नकली रूपरेखा (MockingApi) और एक मुखर पुस्तकालय है;
  • पैरामीटर परीक्षण लिखने के लिए स्पॉक भी बहुत अच्छा है:

def "maximum of two numbers"() {
    expect:
    Math.max(a, b) == c

    where:
    a | b | c
    1 | 3 | 3
    7 | 4 | 7
    0 | 0 | 0
  }

यह एक बहुत ही सतही तुलना है (यदि इसे तुलना कहा जा सकता है), लेकिन ये मोटे तौर पर यही कारण हैं कि हमने स्पॉक को क्यों चुना। स्वाभाविक रूप से, बाद के हफ्तों और महीनों में हमें कुछ कठिनाइयों का सामना करना पड़ा।

कोटलिन को स्पॉक के साथ परीक्षण करने और उन्हें हल करने में समस्याओं का सामना करना पड़ा


यहां मैं तुरंत एक आरक्षण करता हूं कि नीचे वर्णित समस्याएं स्पॉक के लिए अद्वितीय नहीं हैं, वे किसी भी जावा फ्रेमवर्क के लिए प्रासंगिक होंगे और वे मुख्य रूप से कोटलिन के साथ संगतता के साथ जुड़े हुए हैं

1. डिफ़ॉल्ट रूप से अंतिम




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

इसलिए, यदि आपके पास एक सेवा है:

class CustomerService {
    fun getCustomer(id: String): Customer {
        // Some logic
    }
}

और आप ग्रूवी में इस सेवा का मज़ाक बनाने की कोशिश करते हैं:

def customerServiceMock = Mock(CustomerService)

तब आपको एक त्रुटि मिलती है:
org.spockframework.mock.CannotCreateMockException: Cannot create mock for class CustomerService because Java mocks cannot mock final classes

फेसला:

  • , , open, . «» , , , , ;
  • all-open . . Spring Framework Hibernate, cglib(Code Generation Library);
  • , mock-, Kotlin (, mockk). , , Spock Spock MockingApi.

2.


समस्या

कोटलिन में, फ़ंक्शन या कंस्ट्रक्टर तर्क में डिफ़ॉल्ट मान हो सकते हैं जो कि फ़ंक्शन तर्क निर्दिष्ट किए जाने पर उपयोग किए जाते हैं। कठिनाई यह है कि जावा बाइटकोड डिफ़ॉल्ट तर्क मान और फ़ंक्शन पैरामीटर नाम खो देता है, और इसलिए, स्पॉक से फ़ंक्शन या कोटलिन कंस्ट्रक्टर को कॉल करते समय, सभी मानों को स्पष्ट रूप से निर्दिष्ट किया जाना चाहिए।

एक ऐसे वर्ग पर विचार करें Customerजिसमें 2 अनिवार्य फ़ील्ड emailऔर nameडिफ़ॉल्ट मान वाले वैकल्पिक फ़ील्ड हैं:

data class Customer(
    val email: String,
    val name: String,
    val surname: String = "",
    val age: Int = 18,
    val identifiers: List<NationalIdentifier> = emptyList(),
    val addresses: List<Address> = emptyList(),
    val paymentInfo: PaymentInfo? = null
)

ग्रूवी स्पॉक टेस्ट में इस वर्ग का एक उदाहरण बनाने के लिए, आपको कंस्ट्रक्शन के सभी तर्कों के लिए मान पास करना होगा:

new Customer("john.doe@gmail.com", "John", "", 18, [], [], null)

फेसला:


class ModelFactory {
    static def getCustomer() { 
        new Customer(
            "john.doe@gmail.com", 
            "John", 
            "Doe", 
            18, 
            [nationalIdentifier], 
            [address], 
            paymentInfo
        ) 
    }

    static def getAddress() { new Address(/* arguments */) }

    static def getNationalIdentifier() { new NationalIdentifier(/* arguments */) }

    static def getPaymentInfo() { new PaymentInfo(/* arguments */) }
}

3. Java Reflection vs Kotlin Reflection


यह काफी संकीर्ण क्षेत्र हो सकता है, लेकिन यदि आप अपने परीक्षणों में प्रतिबिंब का उपयोग करने की योजना बनाते हैं, तो आपको विशेष रूप से सोचना चाहिए कि क्या ग्रूवी का उपयोग करना है। हमारी परियोजना में, हम बहुत सारे एनोटेशन का उपयोग करते हैं और, कुछ वर्गों या कुछ क्षेत्रों को एनोटेशन के साथ एनोटेट करने के लिए मत भूलना, हम प्रतिबिंब का उपयोग करके परीक्षण लिखते हैं। यहीं से मुश्किलें पैदा होती हैं।

समस्या

कक्षाएं और एनोटेशन कोटलिन में लिखे गए हैं, ग्रूवी में परीक्षण और प्रतिबिंब से संबंधित तर्क। इस वजह से, परीक्षण जावा परावर्तन एपीआई और कोटलिन प्रतिबिंब से एक हैश उत्पन्न करता है:

जावा कक्षाओं को कोटलिन में परिवर्तित करना:

def kotlinClass = new KClassImpl(clazz)

स्थिर तरीकों के रूप में कोटलिन एक्सटेंशन कार्यों को कॉल करना:
ReflectJvmMapping.getJavaType(property.returnType)

हार्ड-टू-रीड कोड जहां कोटलिन प्रकारों का उपयोग किया जाएगा:
private static boolean isOfCollectionType(KProperty1<Object, ?> property) {
    // Some logic
}

बेशक, यह कुछ अत्यधिक या असंभव नहीं है। एकमात्र सवाल यह है कि क्या कोटलिन परीक्षण ढांचे के साथ ऐसा करना आसान नहीं है, जहां विस्तार कार्यों और शुद्ध कोटलिन प्रतिबिंब का उपयोग करना संभव होगा ??

4. कोराटाइन


यदि आप कोरटाइन का उपयोग करने की योजना बनाते हैं, तो यह सोचने का एक और कारण है कि क्या आप परीक्षण के लिए कोटलिन ढांचे को चुनना चाहते हैं।

समस्या

यदि आप एक suspendसमारोह बनाते हैं:

suspend fun someSuspendFun() {
    // Some logic
}

, तो यह इस प्रकार है:

public void someSuspendFun(Continuation<? super Unit> $completion) {
    // Some logic
}

जहां कॉन्टिनेशन एक जावा क्लास है जो कोरटाइन को निष्पादित करने के लिए तर्क को एनकैप्सुलेट करता है। यह वह जगह है जहां समस्या उत्पन्न होती है, इस वर्ग की वस्तु कैसे बनाएं? इसके अलावा, ग्रूवी में रनबॉकिंग उपलब्ध नहीं है और इसलिए यह आमतौर पर बहुत स्पष्ट नहीं है कि स्पॉक में कोरआउट के साथ कोड का परीक्षण कैसे किया जाए।

सारांश


स्पॉक का उपयोग करने के छह महीनों में, यह हमें खराब से अधिक अच्छा लाया और हमें इस विकल्प पर पछतावा नहीं है: परीक्षण पढ़ने और बनाए रखने में आसान है, पैरामीटर परीक्षण लिखना एक खुशी है। हमारे मामले में मरहम में एक मक्खी प्रतिबिंब बन गई, लेकिन इसका उपयोग केवल कुछ स्थानों पर किया जाता है, कोरटाइन के साथ भी।

कोटलिन पर विकसित की जा रही एक परियोजना के परीक्षण के लिए एक रूपरेखा का चयन करते समय, आपको ध्यान से सोचना चाहिए कि आप किस भाषा की सुविधाओं का उपयोग करने की योजना बना रहे हैं। यदि आप एक साधारण CRUD एप्लिकेशन लिख रहे हैं, तो Spock एक सही समाधान है। क्या आप coroutines और प्रतिबिंब का उपयोग करते हैं? फिर स्पेक या कोटेस्ट में बेहतर देखें

सामग्री पूर्ण होने का दावा नहीं करती है, इसलिए यदि आपको Spock और Kotlin का उपयोग करते समय अन्य कठिनाइयों का सामना करना पड़ा है - टिप्पणियों में लिखें।

उपयोगी कड़ियाँ



All Articles