एक कहानी को एक अच्छा विचार बताने के लिए इकाई परीक्षणों का उपयोग कर रहा है?


13

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

  • RequiresLogin_should_redirect_when_not_logged_in
  • RequiresLogin_should_pass_through_when_logged_in
  • Login_should_work_when_given_proper_credentials

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

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

उदाहरण के लिए, यह एक परीक्षण स्टब है जिसे मैं लेकर आया था:

public class Authentication_Bill
{
    public void Bill_has_no_account() 
    { //assert username "bill" not in UserStore
    }
    public void Bill_attempts_to_post_comment_but_is_redirected_to_login()
    { //Calls RequiredLogin and should redirect to login page
    }
    public void Bill_creates_account()
    { //pretend the login page doubled as registration and he made an account. Add the account here
    }
    public void Bill_logs_in_with_new_account()
    { //Login("bill", "password"). Assert not redirected to login page
    }
    public void Bill_can_now_post_comment()
    { //Calls RequiredLogin, but should not kill request or redirect to login page
    }
}

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

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


4
इकाई, एकीकरण और कार्यात्मक परीक्षण के बीच लाइनों धुँधली कर रहे हैं, अगर मैं चाहता हूँ करने के लिए है अपने परीक्षण ठूंठ के लिए एक नाम चुनें, उस पर काम करना चाहते हैं।
यनीस २३'१३ को

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

1
मैंने अरेंज / एक्ट / एस्टर पैटर्न का उपयोग करते हुए इकाई परीक्षण लिखने के अधिक पारंपरिक तरीके पर विवरण के साथ उत्तर लिखा है, लेकिन एक मित्र को github.com/cucumber/cucumber/wiki/Gherkin का उपयोग करके बहुत सफलता मिली है , जो है चश्मा और afaik के लिए इस्तेमाल ककड़ी परीक्षण उत्पन्न कर सकते हैं।
स्टुपरयूजर

हालांकि मैं आपके द्वारा बताए गए तरीके का उपयोग नहीं करूंगा या nunit या समान के साथ दिखाया गया है, nspec को संदर्भ बनाने और अधिक कहानी चालित प्रकृति में परीक्षण के लिए समर्थन प्राप्त है: nspec.org
माइक

1
"बिल" को "उपयोगकर्ता" में बदलें और आप कर रहे हैं
स्टीवन ए लोवे

जवाबों:


15

हां, यह आपके परीक्षण का उदाहरण है कि आप जिन उदाहरण परिदृश्यों का परीक्षण कर रहे हैं उनका नाम दें। और आपके यूनिट परीक्षण उपकरण का उपयोग सिर्फ यूनिट परीक्षणों से अधिक के लिए ठीक है, शायद, बहुत सारे लोग सफलता के साथ ऐसा करते हैं (मुझे भी)।

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

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

संपादित करें: बेशक, यह आपके परीक्षणों की "कहानी" प्रकृति के खिलाफ लगता है, लेकिन यदि आप अपने सहायक तरीकों को सार्थक नाम देते हैं, तो आप प्रत्येक परीक्षण के भीतर अपनी कहानियों को ढूंढते हैं।

तो, यह इस तरह दिखना चाहिए:

[TestFixture]
public class Authentication_Bill
{
    [Setup]
    public void Init()
    {  // bring the system in a predefined state, with noone logged in so far
    }

    [Test]
    public void Test_if_Bill_can_create_account()
    {
         CreateAccountForBill();
         // assert that the account was created properly 
    }

    [Test]
    public void Test_if_Bill_can_post_comment_after_login()
    { 
         // here is the "story" now
         CreateAccountForBill();
         LoginWithBillsAccount();
         AddCommentForBill();
        //  assert that the right things happened
    }

    private void CreateAccountForBill()
    {
        // ...
    }
    // ...
}

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

4

इकाई परीक्षणों के साथ एक कहानी बताने में एक समस्या यह है कि यह स्पष्ट नहीं करता है कि इकाई परीक्षणों को व्यवस्थित किया जाना चाहिए और पूरी तरह से एक दूसरे से स्वतंत्र रूप से चलना चाहिए।

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

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

अधिक गहराई में एक अच्छा लेख गंदा संकर परीक्षणों पर क्लासिक है ।

वर्गों, विधियों और परिणामों को पठनीय बनाने के लिए महान कला इकाई परीक्षण नामकरण सम्मेलन का उपयोग करता है

टेस्ट क्लास:

ClassUnderTestTests

परीक्षण विधियाँ:

MethodUnderTest_Condition_ExpectedResult

@ डॉक ब्राउन के उदाहरण की प्रतिलिपि बनाने के लिए, [सेटअप] का उपयोग करने के बजाय जो प्रत्येक परीक्षण से पहले चलता है, मैं परीक्षण करने के लिए अलग-अलग ऑब्जेक्ट बनाने के लिए सहायक तरीके लिखता हूं।

[TestFixture]
public class AuthenticationTests
{
    private Authentication GetAuthenticationUnderTest()
    {
        // create an isolated Authentication object ready for test
    }

    [Test]
    public void CreateAccount_WithValidCredentials_CreatesAccount()
    {
         //Arrange
         Authentication codeUnderTest = GetAuthenticationUnderTest();
         //Act
         Account result = codeUnderTest.CreateAccount("some", "valid", "data");
         //Assert
         //some assert
    }

    [Test]
    public void CreateAccount_WithInvalidCredentials_ThrowsException()
    {
         //Arrange
         Authentication codeUnderTest = GetAuthenticationUnderTest();
         Exception result;
         //Act
         try
         {
             codeUnderTest.CreateAccount("some", "invalid", "data");
         }
         catch(Exception e)
         {
             result = e;
         }
         //Assert
         //some assert
    }
}

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

इसी तरह मैंने हमेशा यूनिट टेस्ट लिखे हैं, लेकिन एक दोस्त को गेरकिन के साथ बहुत सफलता मिली है ।


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

3

क्या आप मुझे इकाई परीक्षण की तुलना में व्यवहार प्रेरित डिजाइन (BDD) की तरह लग रहा है का वर्णन कर रहे हैं । पर एक नजर डालें SpecFlow जो एक .NET BDD तकनीक है कि पर आधारित है खीरा डीएसएल।

शक्तिशाली सामान जिसे कोई भी मानव कोडिंग के बारे में कुछ भी जाने बिना पढ़ / लिख सकता है। हमारी परीक्षण टीम हमारे एकीकरण परीक्षण सुइट्स के लिए इसे प्राप्त करने में बड़ी सफलता प्राप्त कर रही है।

इकाई परीक्षणों के सम्मेलनों के संबंध में, @ DocBrown का उत्तर ठोस प्रतीत होता है।


जानकारी के लिए, BDD बिल्कुल TDD की तरह है, यह सिर्फ लेखन शैली है जो बदल जाती है। उदाहरण: TDD = assert(value === expected)BDD = value.should.equals(expected)+ आप परतों में उन विशेषताओं का वर्णन करते हैं जो "इकाई परीक्षण स्वतंत्रता" समस्या को हल करते हैं। यह एक महान शैली है!
8
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.