एकल परीक्षण के लिए यूनिट के लिए सिंगल या मल्टीपल फाइल्स?


20

अपने संगठन के लिए दिशानिर्देशों को एक साथ रखने में मदद करने के लिए सर्वोत्तम प्रथाओं का शोध करने वाली इकाई में, मैंने इस सवाल में भाग लिया है कि क्या यह परीक्षण जुड़नार (परीक्षण कक्षाओं) को अलग करना या एक ही कक्षा में एक ही कक्षा के लिए सभी परीक्षणों को रखने के लिए बेहतर या उपयोगी है।

Fwiw, मैं शुद्ध अर्थ में "यूनिट परीक्षणों" का उल्लेख कर रहा हूं कि वे एक वर्ग को लक्षित करने वाले सफेद-बॉक्स परीक्षण हैं, प्रति परीक्षण एक जोर, सभी निर्भरता का मजाक उड़ाया गया है, आदि।

एक उदाहरण परिदृश्य एक वर्ग है (इसे दस्तावेज़ कहते हैं) जिसमें दो विधियाँ हैं: CheckIn और CheckOut। प्रत्येक विधि विभिन्न नियमों को लागू करती है, आदि जो उनके व्यवहार को नियंत्रित करते हैं। एक-प्रति-परीक्षण नियम के बाद, मेरे पास प्रत्येक विधि के लिए कई परीक्षण होंगे। मैं या तो सभी परीक्षणों को एक ही DocumentTestsवर्ग में रख सकता हूं , जैसे नाम CheckInShouldThrowExceptionWhenUserIsUnauthorizedऔर CheckOutShouldThrowExceptionWhenUserIsUnauthorized

या, मेरे पास दो अलग-अलग परीक्षण कक्षाएं हो सकती हैं: CheckInShouldऔर CheckOutShould। इस स्थिति में, मेरे परीक्षण के नाम को छोटा कर दिया जाएगा, लेकिन वे एक विशिष्ट व्यवहार (विधि) के लिए सभी परीक्षण एक साथ आयोजित किए जाएंगे।

मुझे यकीन है कि प्रो और कोन दोनों के पास पहुंच रहे हैं और सोच रहे हैं कि क्या किसी ने कई फाइलों के साथ रास्ता तय किया है और यदि हां, तो क्यों? या, यदि आपने एकल फ़ाइल दृष्टिकोण का विकल्प चुना है, तो आपको ऐसा क्यों लगता है कि यह बेहतर है?


2
आपके परीक्षण विधि के नाम बहुत लंबे हैं। उन्हें सरल करें, भले ही इसका मतलब है कि एक परीक्षा पद्धति में कई दावे होंगे।
बर्नार्ड

12
@ बर्नार्ड: इसे प्रति पद्धति में कई जोर देने के लिए बुरा अभ्यास माना जाता है, लंबे परीक्षण विधि के नाम को हालांकि बुरा अभ्यास नहीं माना जाता है। हम आमतौर पर दस्तावेज़ का नाम में परीक्षण कर रहे हैं कि क्या विधि है। Eg constructor_nullSomeList (), setUserName_UserNameIsNotValid () आदि ...
c_maker

4
@ बर्नार्ड: मैं लंबे परीक्षण नामों का उपयोग करता हूं (और केवल वहां!) भी। मैं उनसे प्यार करता हूं, क्योंकि यह स्पष्ट है कि क्या काम नहीं कर रहा था (यदि आपके नाम अच्छे विकल्प हैं;))।
सेबस्टियन बाउर

यदि वे सभी एक ही परिणाम का परीक्षण करते हैं, तो कई दावे एक बुरा अभ्यास नहीं हैं। उदाहरण के लिए। आप नहीं होगा testResponseContainsSuccessTrue(), testResponseContainsMyData()और testResponseStatusCodeIsOk()। आप किसी एक में उन्हें करना होगा testResponse(): गया है जो तीन का दावा है assertEquals(200, response.status), assertEquals({"data": "mydata"}, response.data)औरassertEquals(true, response.success)
जुहा Untinen

जवाबों:


18

यह दुर्लभ है, लेकिन कभी-कभी यह समझ में आता है कि किसी दिए गए वर्ग के लिए परीक्षण के तहत कई परीक्षण कक्षाएं हैं। आमतौर पर मैं ऐसा तब करता हूं जब विभिन्न सेटअप की आवश्यकता होती है, और परीक्षणों के सबसेट में साझा किया जाता है।


3
अच्छा उदाहरण है कि क्यों मुझे पहली बार में दृष्टिकोण प्रस्तुत किया गया था। उदाहरण के लिए, जब मैं चेकइन विधि का परीक्षण करना चाहता हूं, तो मैं हमेशा चाहता हूं कि परीक्षण के तहत वस्तु को एक तरह से सेटअप किया जाए, लेकिन जब मैं चेकऑउट पद्धति का परीक्षण करता हूं, तो मुझे एक अलग सेटअप की आवश्यकता होती है। अच्छी बात।
SonOfPirate

14

वास्तव में किसी भी सम्मोहक कारण को नहीं देख सकते हैं कि आप किसी एकल वर्ग के लिए एक परीक्षा को कई परीक्षा-कक्षाओं में क्यों विभाजित करेंगे। चूंकि ड्राइविंग आइडिया को क्लास-लेवल पर सामंजस्य बनाए रखना चाहिए, इसलिए आपको टेस्ट-लेवल पर भी इसके लिए प्रयास करना चाहिए। बस कुछ यादृच्छिक कारण:

  1. सेट-अप कोड को डुप्लिकेट (और कई संस्करणों को बनाए रखने) की आवश्यकता नहीं है
  2. एक IDE से एक वर्ग के लिए सभी परीक्षण चलाने के लिए आसान अगर वे एक परीक्षण-वर्ग में समूह हैं
  3. परीक्षण-कक्षाओं और कक्षाओं के बीच एक-से-एक मैपिंग के साथ आसान समस्या निवारण।

अच्छे अंक। यदि परीक्षण के तहत कक्षा एक भयानक कीचड़ है, तो मैं कई परीक्षण कक्षाओं को खारिज नहीं करूंगा, जहां उनमें से कुछ में सहायक तर्क हैं। मुझे बहुत कठोर नियम पसंद नहीं हैं। इसके अलावा, महान अंक।
अय्यूब

1
मैं एक एकल वर्ग के खिलाफ काम कर रहे जुड़नार के लिए एक सामान्य आधार वर्ग होने से डुप्लिकेट सेटअप कोड को समाप्त कर दूंगा। निश्चित नहीं है कि मैं अन्य दो बिंदुओं से बिल्कुल सहमत हूँ।
SonOfPirate

JUnit उदा में आप विभिन्न रनर का उपयोग करके चीजों का परीक्षण करना चाह सकते हैं जिससे विभिन्न वर्गों की आवश्यकता होती है।
जोआचिम निल्सन

जैसा कि मैं प्रत्येक में जटिल गणित के साथ बड़ी संख्या में विधियों के साथ एक वर्ग लिखता हूं, मुझे लगता है कि मेरे पास 85 परीक्षण हैं और अब तक केवल 24% विधियों के लिए लिखित परीक्षाएं हैं। मैं अपने आप को यहां पाता हूं क्योंकि मैं सोच रहा था कि क्या इसका पागल किसी भी तरह से अलग-अलग श्रेणियों में परीक्षणों की इस भारी संख्या को कांटा कर सकता है ताकि मैं सबसेट चला सकूं।
मूविंग डक

7

यदि आप एक से अधिक फ़ाइलों के लिए एक वर्ग के लिए इकाई परीक्षणों को विभाजित करने के लिए मजबूर हैं, तो यह एक संकेत हो सकता है कि वर्ग स्वयं खराब तरीके से डिज़ाइन किया गया है। मैं किसी भी परिदृश्य के बारे में नहीं सोच सकता जहाँ एक वर्ग के लिए यूनिट परीक्षणों को विभाजित करने के लिए यह अधिक फायदेमंद होगा जो यथोचित रूप से एकल जिम्मेदारी सिद्धांत और अन्य प्रोग्रामिंग सर्वोत्तम प्रथाओं का पालन करता है।

इसके अलावा, इकाई परीक्षणों में लंबी विधि के नाम स्वीकार्य हैं, लेकिन अगर यह आपको परेशान करता है, तो आप हमेशा नामों को छोटा करने के लिए अपने यूनिट परीक्षण नामकरण सम्मेलन को पुनर्विचार कर सकते हैं।


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

3
यकीन नहीं होता कि यहां एसआरपी कैसे संबंधित है। मेरी कक्षा में कई तरीके हैं और मुझे उन सभी आवश्यकताओं के लिए यूनिट टेस्ट लिखने की ज़रूरत है जो उनके व्यवहार को चलाते हैं। क्या 50 टेस्ट मेथड के साथ एक टेस्ट क्लास या 10 टेस्ट के साथ 5 टेस्ट क्लास होना बेहतर है जो टेस्ट के तहत क्लास में एक विशिष्ट विधि से संबंधित हो?
SonOfPirate

2
@SonOfPirate: यदि आपको बहुत सारे परीक्षणों की आवश्यकता है, तो इसका मतलब हो सकता है कि आपके तरीके बहुत अधिक कर रहे हैं। इसलिए एसआरपी यहां बहुत प्रासंगिक है। यदि आप एसआरपी को कक्षाओं के साथ-साथ विधियों पर भी लागू करते हैं, तो आपके पास बहुत सी छोटी कक्षाएं और विधियाँ होंगी जो परीक्षण करना आसान है और आपको इतने सारे परीक्षण तरीकों की आवश्यकता नहीं होगी। (लेकिन मैं Péter Török से सहमत हूं कि जब आप विरासत कोड का परीक्षण करते हैं, तो अच्छी प्रथाएं दरवाजे से बाहर हो जाती हैं और आपको बस वही अच्छा करना होता है जो आपको दिया जाता है ...)
c_maker

सबसे अच्छा उदाहरण मैं दे सकता हूं चेकइन विधि, जहां हमारे पास व्यावसायिक नियम हैं जो यह निर्धारित करते हैं कि किस व्यक्ति को कार्रवाई करने की अनुमति है (प्राधिकरण), यदि वस्तु को उचित स्थिति में चेक किया जाना है जैसे कि यह चेक-आउट और यदि परिवर्तन है किया गया है। हमारे पास इकाई परीक्षण होंगे जो प्राधिकरण नियमों को सत्यापित करते हैं और साथ ही यह जांचने के लिए परीक्षण लागू किए जा रहे हैं कि विधि सही ढंग से व्यवहार करती है यदि चेकइन को कहा जाता है जब ऑब्जेक्ट चेक-आउट नहीं किया जाता है, तो बदला नहीं जाता है, यही कारण है कि हम कई के साथ समाप्त होते हैं परीक्षण। क्या आप यह सुझाव दे रहे हैं कि यह गलत है?
SonOfPirate

मुझे नहीं लगता कि इस विषय पर कठिन और तेज़, सही या गलत जवाब हैं। यदि आप जो कर रहे हैं वह आपके लिए काम कर रहा है, तो यह बहुत अच्छा है। यह एक सामान्य दिशानिर्देश पर मेरा दृष्टिकोण है।
FishBasketGordo

2

परीक्षणों को कई वर्गों में अलग करने के खिलाफ मेरा एक तर्क यह है कि मौजूदा परीक्षणों का पता लगाने के लिए टीम पर अन्य डेवलपर्स के लिए कठिन हो जाता है (विशेषकर वे जो टेस्ट सेवी के रूप में नहीं हैं) मुझे आश्चर्य है कि क्या इसके लिए पहले से ही एक परीक्षण है विधि; मुझे आश्चर्य है कि यह कहाँ होगा? ) और यह भी कि नई परीक्षाएँ कहाँ रखी जाएँ ( मैं इस कक्षा में इस पद्धति के लिए एक परीक्षा लिखने जा रहा हूँ, लेकिन यह निश्चित नहीं है कि मैं उन्हें एक नई फ़ाइल, या किसी मौजूदा फ़ाइल में डालूँ या नहीं। एक? )

ऐसे मामले में जहां अलग-अलग परीक्षणों के लिए अलग-अलग सेटअप की आवश्यकता होती है, मैंने देखा है कि टीडीडी के कुछ चिकित्सकों ने "स्थिरता" या "सेटअप" को अलग-अलग कक्षाओं / फाइलों में रखा है, लेकिन स्वयं परीक्षणों में नहीं।


1

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

यहाँ एक उदाहरण है कि यह दृष्टिकोण मेरे मूल परिदृश्य पर कैसे लागू होता है:

public abstract class DocumentTests : TestBase
{
    [TestClass()]
    public sealed class CheckInShould : DocumentTests
    {
        [TestMethod()]
        public void ThrowExceptionWhenUserIsNotAuthorized()
        {
        }
    }

    [TestClass()]
    public sealed class CheckOutShould : DocumentTests
    {
        [TestMethod()]
        public void ThrowExceptionWhenUserIsNotAuthorized()
        {
        }
    }
}

इसका परिणाम परीक्षण सूची में आने वाले निम्नलिखित परीक्षणों में होता है:

DocumentTests+CheckInShould.ThrowExceptionWhenUserIsNotAuthorized
DocumentTests+CheckOutShould.ThrowExceptionWhenUserIsNotAuthorized

जैसे-जैसे अधिक परीक्षण जोड़े जाते हैं, उन्हें आसानी से वर्गीकृत किया जाता है और वर्ग के नाम से क्रमबद्ध किया जाता है जो एक साथ सूचीबद्ध परीक्षण के तहत कक्षा के लिए सभी परीक्षण भी रखता है।

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


1

एक मिनट के लिए दूसरे तरीके से सोचने की कोशिश करें।

आपके पास प्रति कक्षा केवल एक परीक्षा कक्षा क्यों होगी? क्या आप एक क्लास टेस्ट या एक यूनिट टेस्ट कर रहे हैं? क्या आप कक्षाओं पर भी निर्भर हैं ?

एक इकाई परीक्षण एक विशिष्ट संदर्भ में, एक विशिष्ट व्यवहार का परीक्षण करने वाला माना जाता है। तथ्य यह है कि आपकी कक्षा में पहले से ही एक CheckInसाधन है, ऐसा व्यवहार होना चाहिए जो इसे पहली जगह में चाहिए।

आप इस छद्म कोड के बारे में कैसे सोचेंगे:

// check_in_test.file

class CheckInTest extends TestCase {
        /** @test */
        public function unauthorized_users_cannot_check_in() {
                $this->expectException();

                $document = new Document($unauthorizedUser);

                $document->checkIn();
        }
}

अब आप सीधे checkInविधि का परीक्षण नहीं कर रहे हैं । आप इसके बजाय एक व्यवहार का परीक्षण कर रहे हैं (जो सौभाग्य से जांचना है;)), और यदि आपको Documentइसे अलग-अलग वर्गों में परावर्तित और विभाजित करने की आवश्यकता है , या किसी अन्य वर्ग को इसमें मिला दें, तो आपकी परीक्षण फ़ाइलें अभी भी सुसंगत हैं, फिर भी वे समझ में आते हैं आप कभी भी तर्क को बदल नहीं रहे हैं जब केवल संरचना है।

एक वर्ग के लिए एक परीक्षण फ़ाइल को केवल जब भी आपको आवश्यकता होती है, रिफ्लेक्टर करना कठिन हो जाता है, और परीक्षण भी कोड के डोमेन / तर्क की अवधि में कम समझ में आता है।


0

सामान्य तौर पर मैं एक विधि के बजाय कक्षा के व्यवहार के परीक्षण के रूप में परीक्षणों के बारे में सोचने की सलाह दूंगा। यानी कुछ अपेक्षित व्यवहार का परीक्षण करने के लिए आपके कुछ परीक्षणों को कक्षा में दोनों तरीकों को कॉल करने की आवश्यकता हो सकती है।

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


0

1. विचार करें कि क्या गलत होने की संभावना है

प्रारंभिक विकास के दौरान, आप अच्छी तरह से जानते हैं कि आप क्या कर रहे हैं और दोनों समाधान शायद ठीक काम करेंगे।

यह तब और दिलचस्प हो जाता है जब एक परीक्षण बहुत बाद में विफल हो जाता है। दो संभावनाएँ हैं:

  1. आप गंभीरता से टूट गए हैं CheckIn(या CheckOut)। फिर, दोनों एकल-फ़ाइल के साथ-साथ दो-फ़ाइल समाधान उस स्थिति में ठीक हैं।
  2. आपने दोनों CheckInऔर CheckOut(और शायद उनके परीक्षणों को) एक तरह से संशोधित किया है जो उनमें से प्रत्येक के लिए समझ में आता है, लेकिन दोनों के लिए एक साथ नहीं। आपने जोड़ी के सामंजस्य को तोड़ा है। उस स्थिति में, दो फ़ाइलों पर परीक्षणों को विभाजित करने से समस्या को समझना कठिन हो जाएगा।

2. विचार करें कि परीक्षण किस लिए उपयोग किए जाते हैं

टेस्ट दो मुख्य उद्देश्य हैं:

  1. स्वचालित रूप से प्रोग्राम की जांच करें अभी भी सही ढंग से काम करता है। क्या परीक्षण एक फ़ाइल में हैं या कई इस उद्देश्य के लिए मायने नहीं रखते हैं।
  2. एक मानवीय पाठक को कार्यक्रम की समझ बनाने में मदद करें। यह बहुत आसान होगा अगर बारीकी से संबंधित कार्यक्षमता के लिए परीक्षणों को एक साथ रखा जाए, क्योंकि उनके सुसंगतता को समझना समझ का एक तीव्र मार्ग है।

इसलिए?

इन दोनों दृष्टिकोणों का सुझाव है कि परीक्षण एक साथ रखने से मदद मिल सकती है, लेकिन चोट नहीं पहुंचेगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.