2009-07-29 11 views
6

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

मेरे पास एक तरीका है जो उपयोगकर्ता द्वारा अपना पासवर्ड भूल जाने पर एक पासवर्ड रीसेट टोकन उत्पन्न करता है। विधि दो चीजों में से एक लौटाती है: कुछ भी नहीं (शून्य) अगर सबकुछ ठीक काम करता है, या एक त्रुटि कोड यह दर्शाता है कि निर्दिष्ट उपयोगकर्ता नाम वाला उपयोगकर्ता मौजूद नहीं है।

यदि मैं केवल सार्वजनिक इंटरफ़ेस का परीक्षण कर रहा हूं, तो मैं कैसे सुनिश्चित कर सकता हूं कि पासवर्ड रीसेट टोकन डेटाबेस में जा रहा है यदि उपयोगकर्ता नाम मान्य है, और यदि उपयोगकर्ता नाम मान्य नहीं है तो डेटाबेस में नहीं जा रहा है? क्या मुझे यह सत्यापित करने के लिए अपने परीक्षणों में प्रश्न पूछना चाहिए? या क्या मुझे लगता है कि मेरा तर्क अच्छा है?

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

कोड, संदर्भ के लिए आवश्यक है, तो:

public function generatePasswordReset($username) 
{ 
    $this->sql='SELECT id 
       FROM users 
       WHERE username = :username'; 

    $this->addParam(':username', $username); 
    $user=$this->query()->fetch(); 

    if (!$user) 
     return self::$E_USER_DOESNT_EXIST; 
    else 
    { 
     $code=md5(uniqid()); 
     $this->addParams(array(':uid'  => $user['id'], 
           ':code'  => $code, 
           ':duration' => 24 //in hours, how long reset is valid 
          )); 

     //generate new code, delete old one if present 
     $this->sql ='DELETE FROM password_resets WHERE user_id=:uid;'; 
     $this->sql.="INSERT INTO password_resets (user_id, code, expires) 
        VALUES  (:uid, :code, now() + interval ':duration hours')"; 

     $this->execute(); 
    } 
} 
+1

कम से कम मेरे लिए यूनिट परीक्षण के बारे में सबसे अच्छी बात यह है कि यह आपको दिखाता है कि आपको रिफैक्टर करने की आवश्यकता है। यह हाइलाइट निर्भरताओं में भी मदद करता है। मैं सुझाव दूंगा कि आपका 'चयन' और आपका 'हटाएं + INSERT' को अपने स्वयं के तरीकों से दोबारा संशोधित किया जाना चाहिए, जो कि पासवर्ड पीढ़ी अपने –

+0

@pcampbell में होनी चाहिए - आपकी टिप्पणी एक उत्तर होना चाहिए –

उत्तर

6

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

//1. get the user from the DB 
//2. in a big else, check if user is null 
//3. create a array containing the userID, a code, and expiry 
//4. delete any existing password resets 
//5. create a new password reset 

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

Single Responsibility Principle पर विचार करें: "Do one thing"। यह विधियों के साथ-साथ कक्षाओं पर भी लागू होता है।

मेरा सुझाव हैं, जो आपके generatePasswordReset विधि के लिए पुनर्संशोधित किया जाना चाहिए:

  • एक पूर्व निर्धारित मौजूदा उपयोगकर्ता वस्तु/आईडी दिया जाएगा। इस विधि के बाहर उन सभी सैनिटी जांच करें। एक काम कर।
  • पासवर्ड रीसेट कोड को अपनी विधि में डालें। यह काम की एक इकाई होगी जिसे SELECT, DELETE और INSERT से स्वतंत्र रूप से परीक्षण किया जा सकता है।
  • एक नई विधि बनाएं जिसे OverwriteExistingPwdChangeRequests() कहा जा सकता है जो DELETE + INSERT का ख्याल रखेगा।
+0

मैं जो कह रहा हूं उसे प्राप्त करता हूं, लेकिन तब भी मैं एक ही नाव में रहूंगा। यदि मैं व्यक्तिगत रूप से सभी 2/3 विधियों का परीक्षण कर सकता हूं, तो यह एक विधि का परीक्षण करने से अलग कैसे है जो एक ही काम करता है? यह मेरे उपयोगकर्ता मॉडल वर्ग में है। मान लीजिए कि मैंने अपनी सैनिटी चेक को नियंत्रक में रखा है, मुझे बस अपने परीक्षण को नियंत्रक पक्ष में ले जाना होगा। – ryeguy

0

सामान्य से एक में हो सकता है "नकली" वस्तु आप लागू कर रहे हैं, यह सत्यापित करते हुए यह उम्मीद अनुरोध प्राप्त होते हैं।

इस मामले में मुझे यकीन नहीं है कि आप कितनी उपयोगी हैं, आप दो बार एक ही तर्क लिख रहे हैं ... हमने सोचा कि हमने "पासवर्ड से हटाएं" आदि भेजा है। ओह देखो हम किया था!

हमम, हमने वास्तव में क्या देखा। अगर स्ट्रिंग बुरी तरह से बनाई गई थी, तो हम नहीं जानते!

यह यूनिट परीक्षण कानून के पत्र के खिलाफ हो सकता है, लेकिन मैं डेटाबेस के खिलाफ अलग-अलग प्रश्न पूछकर इन दुष्प्रभावों का परीक्षण करूंगा।

1

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

0

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

3

कारण यह कार्य इकाई परीक्षण के लिए अधिक कठिन है क्योंकि डेटाबेस अद्यतन फ़ंक्शन का दुष्प्रभाव है (यानी परीक्षण के लिए आपके लिए कोई स्पष्ट वापसी नहीं है)।

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

+0

"डेटाबेस का कितना "क्या आपको उन राज्य परिवर्तनों को जांचने में सक्षम होने के लिए लागू करने की आवश्यकता है? पार्सिंग एसक्यूएल? कुछ डेटा नकल तालिकाओं को बनाए रखना? मेरा विचार यह है कि एक वास्तविक डेटाबेस का उपयोग कम काम होने के समाप्त होता है। – djna

+0

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

0

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

0

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

चाल इसलिए कोड को कम करने के लिए है जिसे केवल दुष्प्रभावों के साथ परीक्षण किया जा सकता है। अलग-अलग MyDatabase कक्षा में SQL क्वेरी को अलग और छुपाएं जिसमें कोई व्यावसायिक तर्क नहीं है। इस ऑब्जेक्ट का एक उदाहरण अपने व्यावसायिक तर्क कोड पर पास करें।

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

उदाहरण के लिए SimpleTest (एक php mocking ढांचे) के दस्तावेज़ देखें।

1

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

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

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

संबंधित मुद्दे