क्या एकल इकाई परीक्षण में कई दावे करना ठीक है?


396

इस महान पद के लिए टिप्पणी में , रॉय ओशेरोव ने ओएपीटी परियोजना का उल्लेख किया जो प्रत्येक परीक्षण में प्रत्येक मुखर को चलाने के लिए डिज़ाइन किया गया है।

निम्नलिखित परियोजना के मुख पृष्ठ पर लिखा गया है:

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

और, रॉय ने टिप्पणियों में लिखा:

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

मुझे लगता है कि, कुछ मामले ऐसे होते हैं, जहां कई जोर देने की आवश्यकता होती है (जैसे गार्ड अभिकथन ), लेकिन सामान्य तौर पर मैं इससे बचने की कोशिश करता हूं। आप की राय क्या है? कृपया एक वास्तविक विश्व उदाहरण प्रदान करें जहां कई मुखर वास्तव में आवश्यक हैं


2
आप कई कथनों के बिना कैसे मज़ाक करते हैं? मॉक पर प्रत्येक अपेक्षा अपने आप में एक मुखरता है, जिसमें आपके द्वारा लगाए गए कॉल का कोई भी आदेश शामिल है।
क्रिस्टोफर क्रुत्जिग

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

3
मुझे लगता है कि अंगूठे के एक सामान्य नियम के रूप में आपको प्रति परीक्षण परख की संख्या को कम करने की कोशिश करनी चाहिए। हालांकि, जब तक परीक्षण पर्याप्त रूप से कोड में एक विशिष्ट स्थान पर समस्या को बताता है, तब तक यह एक उपयोगी परीक्षा है।
ConditionRacer

2
मैंने ऐसे मामलों को देखा है, जहां विभिन्न प्रकार के एज-केस व्यवहारों का परीक्षण करने के लिए RowTest(MbUnit) / TestCase(NUnit) के बजाय कई दावे किए गए थे । नौकरी के लिए उचित उपकरणों का उपयोग करें! (दुर्भाग्य से, MSTest के पास अभी तक एक पंक्ति-परीक्षण क्षमता नहीं है।)
गांगेय कॉव्बॉय

@GalacticCowboy आप परीक्षण डेटा स्रोतों के उपयोग RowTestऔर TestCaseउपयोग की समान कार्यक्षमता प्राप्त कर सकते हैं । मैं बड़ी सफलता के साथ एक सरल CSV फ़ाइल का उपयोग कर रहा हूँ।
१५:०५ पर जुलैलेगन

जवाबों:


236

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

ऐसा कहने के बाद, मैं कहूंगा कि शायद मेरे आधे परीक्षण वास्तव में केवल एक ही हैं। मुझे लगता है कि यह केवल एक कोड (परीक्षण?) गंध बन जाता है जब आपके परीक्षण में लगभग पांच या अधिक मुखर होते हैं।

आप कई दावे कैसे हल करते हैं?


9
इस उत्तर की तरह - अर्थात इसका ठीक है, लेकिन सामान्य उदाहरण में, अच्छा नहीं है (-:
मर्फ़

5
Ehh? तुम ऐसा क्यों करोगे? विधि निष्पादन बिल्कुल समान है?
१५:३० पर jgauffin

197
प्रति यूनिट परीक्षण के लिए एक एकल जोर पाठक के ऊपर और नीचे स्क्रॉल करने की क्षमता का परीक्षण करने का एक शानदार तरीका है।
टॉम

3
इसके पीछे कोई तर्क? जैसा कि, यह वर्तमान उत्तर बताता है कि यह क्या होना चाहिए, लेकिन क्यों नहीं।
स्टीवन ज्यूरिस

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

295

टेस्ट केवल एक कारण के लिए असफल होना चाहिए, लेकिन इसका मतलब यह नहीं है कि केवल एक Assertबयान होना चाहिए । IMHO " अरेंज, एक्ट, एस्टर " पैटर्न को पकड़ना अधिक महत्वपूर्ण है ।

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

मैं कई मुखर बयानों को देखकर खुश हूं जो एक ही कार्रवाई के परीक्षण के कुछ हिस्सों का निर्माण करते हैं। जैसे

[Test]
public void ValueIsInRange()
{
  int value = GetValueToTest();

  Assert.That(value, Is.GreaterThan(10), "value is too small");
  Assert.That(value, Is.LessThan(100), "value is too large");
} 

या

[Test]
public void ListContainsOneValue()
{
  var list = GetListOf(1);

  Assert.That(list, Is.Not.Null, "List is null");
  Assert.That(list.Count, Is.EqualTo(1), "Should have one item in list");
  Assert.That(list[0], Is.Not.Null, "Item is null");
} 

आप हो सकता है एक ज़ोर में इन गठबंधन है, लेकिन वह यह कहा गया कि आप से एक अलग बात है चाहिए या चाहिए । इनके संयोजन से कोई सुधार नहीं हुआ है।

जैसे पहला वाला हो सकता है

Assert.IsTrue((10 < value) && (value < 100), "Value out of range"); 

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

NB : कोड जो मैं यहां लिख रहा हूं, वह N #nUit के साथ C # है, लेकिन सिद्धांत अन्य भाषाओं और रूपरेखाओं के साथ आयोजित होंगे। वाक्यविन्यास बहुत समान हो सकता है।


32
कुंजी यह है कि आपके पास केवल एक क्रिया है, और फिर आप उस क्रिया के परिणामों का निरीक्षण करते हैं।
अमिताभ

1
मुझे लगता है कि यह भी दिलचस्प है, एक से अधिक मुखर होने के लिए, यदि अरेंज समय महंगा है।
रेक्सिनो

1
@ रेकशिनो, यदि व्यवस्था समय की महँगी है, तो हम व्यवस्था कोड को प्रारंभिक प्रारंभिक दिनचर्या में व्यवस्थित करके, कोड को साझा कर सकते हैं।
शॉन लुटिन

2
इसलिए यदि मैं जैको के उत्तर की तुलना करता हूं, तो "केवल एक मुखर" "मुखरता का केवल एक समूह" बन जाता है जो मेरे लिए अधिक समझ में आता है।
वॉलफ्रैट

2
यह एक अच्छा उत्तर है, लेकिन मैं इस बात से असहमत हूं कि एक भी मुखर बेहतर नहीं है। बुरा मुखर उदाहरण बेहतर नहीं है, लेकिन इसका मतलब यह नहीं है कि सही होने पर एक भी जोर बेहतर नहीं होगा। कई पुस्तकालयों ने कस्टम मुखर / मिलान करने वालों को अनुमति दी है ताकि पहले से मौजूद न होने पर कुछ बनाया जा सके। उदाहरण के लिए Assert.IsBetween(10, 100, value)है कि प्रिंट Expected 8 to be between 10 and 100 है की तुलना में बेहतर दो अलग-अलग मेरी राय में इस बात पर ज़ोर। आप निश्चित रूप से यह तर्क दे सकते हैं कि यह आवश्यक नहीं है, लेकिन यह आम तौर पर विचार करने योग्य है कि क्या उनमें से एक पूरा सेट करने से पहले एक एकल को कम करना आसान है।
Thor84no

85

मैंने कभी नहीं सोचा था कि एक से अधिक मुखर एक बुरी चीज थी।

मुझे हर व़क्त यह करना है:

public void ToPredicateTest()
{
    ResultField rf = new ResultField(ResultFieldType.Measurement, "name", 100);
    Predicate<ResultField> p = (new ConditionBuilder()).LessThanConst(400)
                                                       .Or()
                                                       .OpenParenthesis()
                                                       .GreaterThanConst(500)
                                                       .And()
                                                       .LessThanConst(1000)
                                                       .And().Not()
                                                       .EqualsConst(666)
                                                       .CloseParenthesis()
                                                       .ToPredicate();
    Assert.IsTrue(p(ResultField.FillResult(rf, 399)));
    Assert.IsTrue(p(ResultField.FillResult(rf, 567)));
    Assert.IsFalse(p(ResultField.FillResult(rf, 400)));
    Assert.IsFalse(p(ResultField.FillResult(rf, 666)));
    Assert.IsFalse(p(ResultField.FillResult(rf, 1001)));

    Predicate<ResultField> p2 = (new ConditionBuilder()).EqualsConst(true).ToPredicate();

    Assert.IsTrue(p2(new ResultField(ResultFieldType.Confirmation, "Is True", true)));
    Assert.IsFalse(p2(new ResultField(ResultFieldType.Confirmation, "Is False", false)));
}

यहाँ मैं यह सुनिश्चित करने के लिए कि विभिन्न स्थितियों को अपेक्षित विधेय में बदला जा सकता है, कई ऐसर्ट्स का उपयोग करता हूँ।

मैं केवल एक इकाई ( ToPredicateविधि) का परीक्षण कर रहा हूं, लेकिन मैं वह सब कुछ कवर कर रहा हूं जो मैं परीक्षण में सोच सकता हूं।


46
त्रुटि का पता लगाने के कारण कई एसेर्ट खराब हैं। यदि आप अपने पहले Assert.IsTrue को विफल कर चुके हैं, तो अन्य दावे निष्पादित नहीं किए जाएंगे, और आपको उनसे कोई जानकारी नहीं मिलेगी। दूसरी ओर अगर आपके पास 5 परखनों के साथ 1 के बजाय 5 परीक्षण थे तो आपको कुछ उपयोगी मिल सकता है
Sly

6
क्या आप इसे अभी भी बुरा मानते हैं यदि सभी अभ्रक समान कार्यक्षमता का परीक्षण करते हैं? ऊपर की तरह, उदाहरण सशर्त परीक्षण करता है और यदि इसमें से कोई भी विफल होता है, तो आपको इसे ठीक करना चाहिए। क्या आपके लिए यह मायने रखता है कि यदि आप पहले वाले विफल रहे तो आप अंतिम 2 दावों को याद कर सकते हैं?
चापलूसी

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

19
आपका मामला बहुत ही प्रतिनिधि है, यही कारण है कि NUnit में अतिरिक्त विशेषता TestCase है
nunit.org/?p=testCase&r=2.5

10
Google C ++ टेस्टिंग फ्रेमवर्क में ASSERT () और EXPECT () है। ASSERT () विफल रहता है जबकि EXPECT () जारी है। यह बहुत आसान है जब आप परीक्षण में एक से अधिक चीजों को मान्य करना चाहते हैं।
रतोकोन

21

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

@Test
public void testAlarmSent() {
    assertAllUnitsAvailable();
    assertNewAlarmMessages(0);

    pulseMainProcessor();

    assertAllUnitsAlerting();
    assertAllNotificationsSent();
    assertAllNotificationsUnclosed();
    assertNewAlarmMessages(1);
}

यह उन परिस्थितियों का प्रतिनिधित्व करता है, जिनके लिए मुझे इस प्रक्रिया में हर कदम पर मौजूद रहना चाहिए ताकि मुझे विश्वास हो सके कि कोड मेरी अपेक्षा के अनुरूप व्यवहार कर रहा है। यदि एक भी दावा विफल हो जाता है, तो मुझे परवाह नहीं है कि शेष भी नहीं चलेंगे; क्योंकि सिस्टम की स्थिति अब मान्य नहीं है, इसलिए बाद में किए गए दावे मुझे कुछ भी मूल्यवान नहीं बताएंगे। यदि assertAllUnitsAlerting()मैं असफल रहा, तो मुझे नहीं पता होगा कि assertAllNotificationSent()जब तक मैंने पूर्व त्रुटि का कारण नहीं बनाया था, तब तक मुझे क्या सफलता या विफलता मिली। और इसे सही किया।

(* - ठीक है, वे समस्या को डीबग करने में बोधगम्य रूप से उपयोगी हो सकते हैं। लेकिन सबसे महत्वपूर्ण जानकारी, कि परीक्षण विफल हो गया है, पहले ही प्राप्त हो चुका है।)


जब आप ऐसा करते हैं कि आपको आश्रित परीक्षणों के साथ परीक्षण रूपरेखाओं का उपयोग करना चाहिए, तो यह बेहतर है (उदाहरण के लिए परीक्षण इस सुविधा का समर्थन करता है)
केमोडा

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

इसे मुखर करने के बारे में आपकी क्या राय है। इसे AsarmAlarmStatus (int numberOfAlarmStessess) ??
बोरबज़

1
आपके दावे बहुत अच्छे परीक्षण नामों के लिए होंगे।
ब्योर्न टिपलिंग

अमान्य इनपुट पर भी परीक्षण को चलने देना बेहतर है। यह आपको और अधिक जानकारी प्रदान करता है (और खासकर अगर यह तब भी गुजरता है जब आप इसकी उम्मीद नहीं करते थे)।
कर्टनडॉग

8

एक और कारण है कि मुझे लगता है, कि एक विधि में एक से अधिक जोर देने से कोई बुरी बात नहीं होती है, निम्नलिखित कोड में वर्णित है:

class Service {
    Result process();
}

class Result {
    Inner inner;
}

class Inner {
    int number;
}

अपने परीक्षण में मैं बस यह परीक्षण करना चाहता हूं कि कक्षा service.process()में सही संख्या में रिटर्न Innerआए।

परीक्षण के बजाय ...

@Test
public void test() {
    Result res = service.process();
    if ( res != null && res.getInner() != null ) Assert.assertEquals( ..., res.getInner() );
}

मैं कर रहा हूँ

@Test
public void test() {
    Result res = service.process();
    Assert.notNull(res);
    Assert.notNull(res.getInner());
    Assert.assertEquals( ..., res.getInner() );
}

2
और यह एक अच्छी बात है, आपके परीक्षणों में कोई सशर्त तर्क नहीं होना चाहिए। यह परीक्षण को अधिक जटिल और कम पठनीय बनाता है। और मुझे लगता है कि रॉय ने अपने ब्लॉग पोस्ट में यह सही बताया है कि एक वस्तु पर कई जोर देने से अधिकांश समय ठीक रहता है। तो जो आपके पास है, वे सिर्फ पहरेदार हैं और उनका होना ठीक है।
रेस्टुटा

2
यदि आप Assert.notNullनिरर्थक हैं तो आपका परीक्षण निरर्थक हो जाएगा।
सारा

1
इसके अलावा, अपने पहले उदाहरण (साथ if) यदि पारित करेंगे resहैnull
सारा

1
@kai notNull बेमानी हैं, मैं सहमत हूं, लेकिन मुझे लगता है कि अपवाद के बजाय
मुखर होना

1
अच्छी तरह से एक असफल दावा भी एक अपवाद फेंकता है, और दोनों ही मामलों में आपको सटीक पंक्ति के लिए एक सीधा लिंक मिलता है जो इसे एक साथ एक स्टैक ट्रेस के साथ फेंक देता है इसलिए मैं व्यक्तिगत रूप से परीक्षण को अव्यवस्थित नहीं करूंगा जो कि वैसे भी चेक हो जाएगा। Assert.assertEquals(..., service.process().getInner());अगर लाइन "बहुत लंबी" मिलती है, तो मैं एक ऑनलिनर ला ला को पसंद कर सकता हूं , अगर "बहुत लंबा" हो जाता है
सारा

6

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

उदाहरण के लिए, एक फ़ंक्शन की कल्पना करें जो एक तारीख स्ट्रिंग को पार करता है:

function testParseValidDateYMD() {
    var date = Date.parse("2016-01-02");

    Assert.That(date.Year).Equals(2016);
    Assert.That(date.Month).Equals(1);
    Assert.That(date.Day).Equals(0);
}

यदि परीक्षण विफल रहता है तो यह एक कारण से है, पार्सिंग गलत है। यदि आप यह तर्क देंगे कि यह परीक्षण तीन अलग-अलग कारणों से विफल हो सकता है, तो आप "एक कारण" की परिभाषा में IMHO बहुत ठीक हो जाएंगे।


3

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

आमतौर पर इसका मतलब यह है कि [सेटअप] विधि के अंदर कोड की अंतिम पंक्ति एक संपत्ति मूल्य या वापसी मूल्य को [TestFixture] के एक निजी उदाहरण चर में संग्रहीत करना चाहिए। फिर आप इस उदाहरण चर के बारे में विभिन्न [परीक्षण] विधियों से कई अलग-अलग चीजों का दावा कर सकते हैं। आप यह भी परख सकते हैं कि परीक्षण के तहत वस्तु के विभिन्न गुणों को निर्धारित किया गया है कि वह वांछित स्थिति में है।

कभी-कभी आपको जिस तरह से इच्छित वस्तु में परीक्षण के तहत वस्तु प्राप्त हो रही है, उसी तरह से दावा करने की आवश्यकता है ताकि आप यह सुनिश्चित कर सकें कि आपने वस्तु को वांछित स्थिति में लाने से पहले गड़बड़ नहीं किया है। उस स्थिति में, वे अतिरिक्त दावे [सेटअप] विधि के अंदर प्रकट होने चाहिए। यदि [सेटअप] विधि के अंदर कुछ गलत हो जाता है, तो यह स्पष्ट हो जाएगा कि आपके द्वारा परीक्षण किए जाने वाले इच्छित राज्य में वस्तु प्राप्त होने से पहले परीक्षण में कुछ गड़बड़ थी।

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

उदाहरण (यह कई फ़ाइलों में टूट जाएगा):

namespace Tests.AcctTests
{
    [TestFixture]
    public class no_events
    {
        private Acct _acct;

        [SetUp]
        public void SetUp() {
            _acct = new Acct();
        }

        [Test]
        public void balance_0() {
            Assert.That(_acct.Balance, Is.EqualTo(0m));
        }
    }

    [TestFixture]
    public class try_withdraw_0
    {
        private Acct _acct;
        private List<string> _problems;

        [SetUp]
        public void SetUp() {
            _acct = new Acct();
            Assert.That(_acct.Balance, Is.EqualTo(0));
            _problems = _acct.Withdraw(0m);
        }

        [Test]
        public void has_problem() {
            Assert.That(_problems, Is.EquivalentTo(new string[] { "Withdraw amount must be greater than zero." }));
        }

        [Test]
        public void balance_not_changed() {
            Assert.That(_acct.Balance, Is.EqualTo(0m));
        }
    }

    [TestFixture]
    public class try_withdraw_negative
    {
        private Acct _acct;
        private List<string> _problems;

        [SetUp]
        public void SetUp() {
            _acct = new Acct();
            Assert.That(_acct.Balance, Is.EqualTo(0));
            _problems = _acct.Withdraw(-0.01m);
        }

        [Test]
        public void has_problem() {
            Assert.That(_problems, Is.EquivalentTo(new string[] { "Withdraw amount must be greater than zero." }));
        }

        [Test]
        public void balance_not_changed() {
            Assert.That(_acct.Balance, Is.EqualTo(0m));
        }
    }
}

आप इस मामले में TestCase इनपुट को कैसे संभालते हैं?
साइमन गिल्बेई

इसलिए, मेरे वर्तमान संगठन में, हमारे पास 20,000+ यूनिट परीक्षण हैं जो आप दिखाते हैं। यह एक बुरा सपना है। अधिकांश परीक्षण सेटअप कोड कॉपी / पेस्ट किए जाते हैं, जिसके परिणामस्वरूप गलत परीक्षण सेटअप और अमान्य परीक्षण पास होते हैं। प्रत्येक [Test]विधि के लिए, उस वर्ग को फिर से त्वरित किया जाता है और [SetUp]विधि को फिर से निष्पादित किया जाता है। यह .NET गारबेज कलेक्टर को मारता है और परीक्षण को धीरे-धीरे चलाने का कारण बनता है: स्थानीय रूप से 5+ मिनट, बिल्ड सर्वर पर 20+ मिनट। 20K परीक्षण लगभग 2 - 3 मिनट में चलना चाहिए। मैं इस परीक्षण शैली की सिफारिश नहीं करना चाहता , विशेष रूप से एक बड़े-ईश परीक्षण सूट के लिए।
22 नवंबर को चारपश्चमी की रात

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

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

@ still_dreaming_1 wrt "गैर-जिम्मेदार प्रोग्रामर": मैं मानता हूं कि यह व्यवहार एक बड़ी समस्या है। हालांकि, इस तरह की परीक्षण संरचना वास्तव में इस तरह के व्यवहार को बेहतर या बदतर के लिए आमंत्रित करती है। खराब विकास एक तरफ है, इस रूप में मेरी मुख्य आपत्ति यह है कि यह वास्तव में परीक्षण प्रदर्शन को मारता है। धीमे चलने वाले टेस्ट सूट से बुरा कुछ नहीं है। धीमी गति से चलने वाले परीक्षण सूट का मतलब है कि लोग स्थानीय स्तर पर परीक्षण नहीं चलाएंगे और उन्हें इंटरमीडिएट बिल्ड पर छोड़ने के लिए भी लुभाया जाता है - फिर से, एक लोगों की समस्या, लेकिन ऐसा होता है - जिसे सुनिश्चित करने से सभी को बचा जा सकता है। साथ में।
चारपश्चमी की रात

2

एक ही परीक्षण में कई दावे होने पर केवल एक समस्या होती है जब परीक्षण विफल हो जाता है। फिर आपको परीक्षण को डीबग करना पड़ सकता है या अपवाद का पता लगाने के लिए विश्लेषण कर सकते हैं कि यह कौन सा प्रयास विफल है। प्रत्येक परीक्षा में एक दावे के साथ आमतौर पर यह इंगित करना आसान होता है कि क्या गलत है।

मैं एक ऐसे परिदृश्य के बारे में नहीं सोच सकता, जहां कई मुखरता की वास्तव में आवश्यकता हो , क्योंकि आप हमेशा एक ही दावे में कई स्थितियों के रूप में उन्हें फिर से लिख सकते हैं। हालाँकि यह बेहतर हो सकता है यदि आप उदाहरण के लिए कदमों के बीच के मध्यवर्ती डेटा को सत्यापित करने के बजाय कई कदम उठाते हैं कि खराब इनपुट के कारण बाद के कदम दुर्घटनाग्रस्त हो जाते हैं।


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

@ रीचर्ड: एक परिणाम प्राप्त करना और फिर उस परिणाम से कुछ निकालना कई चरणों में एक प्रक्रिया होगी, इसलिए मैंने उत्तर में दूसरे पैराग्राफ में इसे कवर किया।
गुफ़ा

2
अंगूठे का नियम: यदि आपके पास एक परीक्षण में कई दावे हैं, तो प्रत्येक को एक अलग संदेश होना चाहिए। तब आपको यह समस्या नहीं है।
एन्थोनी

और गुणवत्ता परीक्षण धावक जैसे NCrunch का उपयोग करना आपको वास्तव में दिखाएगा कि परीक्षण में कौन सी रेखा विफल रही, परीक्षण कोड में और परीक्षण के तहत कोड में।
चारपश्चमी रात 21

2

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

String actual = "val1="+val1+"\nval2="+val2;
assertEquals(
    "val1=5\n" +
    "val2=hello"
    , actual
);

यह मुझे एक ही बार में सभी विफल दावे देखने की अनुमति देता है। मैं कई पंक्तियों का उपयोग करता हूं क्योंकि अधिकांश IDE एक साथ संवाद संवाद में स्ट्रिंग अंतर प्रदर्शित करेंगे।


2

यदि आपके पास एकल परीक्षण फ़ंक्शन में कई दावे हैं, तो मैं उनसे सीधे उस परीक्षण के लिए प्रासंगिक होने की अपेक्षा करता हूं जो आप आयोजित कर रहे हैं। उदाहरण के लिए,

@Test
test_Is_Date_segments_correct {

   // It is okay if you have multiple asserts checking dd, mm, yyyy, hh, mm, ss, etc. 
   // But you would not have any assert statement checking if it is string or number,
   // that is a different test and may be with multiple or single assert statement.
}

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


1

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

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


1

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

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

मैंने कभी भी इस तरह के योगों को मददगार नहीं पाया है (कि एक वर्ग को बदलने का एक कारण होना चाहिए बस ऐसे ही एक अप्राप्य विज्ञापन का एक उदाहरण है)। इस बात पर विचार करें कि दो तार बराबर हैं, यह शब्दार्थ यह बताने के बराबर है कि दो तारों की लंबाई समान है और संबंधित सूचकांक में प्रत्येक वर्ण बराबर है।

हम सामान्यीकरण कर सकते हैं और कह सकते हैं कि किसी भी दावे की किसी भी प्रणाली को एक ही दावे के रूप में फिर से लिखा जा सकता है, और किसी भी एक दावे को छोटे अभिकथनों के एक समूह में विघटित किया जा सकता है।

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


0

इसका उत्तर बहुत सरल है - यदि आप एक ऐसे फ़ंक्शन का परीक्षण करते हैं जो एक से अधिक विशेषताओं को बदलता है, एक ही ऑब्जेक्ट या दो अलग-अलग ऑब्जेक्ट्स, और फ़ंक्शन की शुद्धता उन सभी परिवर्तनों के परिणामों पर निर्भर करती है, तो आप दावा करना चाहते हैं उन परिवर्तनों में से हर एक को ठीक से निष्पादित किया गया है!

मुझे एक तार्किक अवधारणा का विचार है, लेकिन रिवर्स निष्कर्ष यह कहेगा कि किसी भी फ़ंक्शन को कभी भी एक वस्तु से अधिक नहीं बदलना चाहिए। लेकिन मेरे अनुभव में सभी मामलों में इसे लागू करना असंभव है।

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

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


-1

यह प्रश्न स्पेगेटी और लसग्ना कोड मुद्दों के बीच संतुलन बनाने की क्लासिक समस्या से संबंधित है।

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

कुछ अपवाद हैं, लेकिन इस मामले में बीच में पेंडुलम रखना जवाब है।


-3

मैं "सामान्य रूप से केवल एक कारण के लिए विफल" से सहमत नहीं हूं। अधिक महत्वपूर्ण बात यह है कि परीक्षण कम हैं और स्पष्ट रूप से imo पढ़ता है।

यह हमेशा प्राप्त करने योग्य नहीं है, हालांकि और जब एक परीक्षण जटिल होता है (लंबा) वर्णनात्मक नाम और कम चीजों का परीक्षण करना अधिक समझ में आता है।

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