2010-02-11 19 views
8

के Mockist परीक्षण लिखने के लिए अगर मैं एक विधि है जो अपने आप एक निश्चित शर्त के तहत कॉल, व्यवहार को सत्यापित करने के लिए एक परीक्षण लिखने के लिए यह संभव है है? मुझे एक उदाहरण देखना अच्छा लगेगा, मुझे नकली ढांचे या भाषा की परवाह नहीं है। मैं सी # में राइनोमोक्स का उपयोग कर रहा हूं इसलिए मैं उत्सुक हूं कि यह ढांचे की एक अनुपलब्ध विशेषता है, या यदि मैं कुछ मौलिक गलत समझ रहा हूं, या यदि यह केवल असंभव है।कैसे एक पुनरावर्ती विधि

+0

यह मेरे लिए स्पष्ट नहीं है। क्या वास्तव में परीक्षण करने की कोशिश कर रहे हैं? यह विधि स्वयं को "कुछ शर्तों के तहत" कहती है (कि "कॉल स्टैक" कुछ निश्चित शर्तों के तहत "एक निश्चित पथ का पालन करेगा) या कुछ और? – Ando

उत्तर

3

मान लिया जाये कि आप उदाहरण के लिए, एक पूर्ण पथ से फ़ाइल नाम मिल की तरह कुछ करना चाहता हूँ:

c:/windows/awesome/lol.cs -> lol.cs 
c:/windows/awesome/yeah/lol.cs -> lol.cs 
lol.cs -> lol.cs 

और तुम हो:

public getFilename(String original) { 
    var stripped = original; 
    while(hasSlashes(stripped)) { 
    stripped = stripped.substringAfterFirstSlash(); 
    } 
    return stripped; 
} 

और आप लिखना चाहते हैं:

public getFilename(String original) { 
    if(hasSlashes(original)) { 
    return getFilename(original.substringAfterFirstSlash()); 
    } 
    return original; 
} 

Recursion यहाँ एक कार्यान्वयन विस्तार है और के लिए परीक्षण नहीं किया जाना चाहिए। आप वास्तव में दो कार्यान्वयन के बीच स्विच करने में सक्षम होना चाहते हैं और यह सत्यापित करते हैं कि वे एक ही परिणाम उत्पन्न करते हैं: दोनों उपरोक्त तीन उदाहरणों के लिए lol.cs का उत्पादन करते हैं।

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

def blah 
    puts "in blah" 
    blah 
end 

alias blah2 blah 

def blah 
    puts "new blah" 
end 

blah2 
+0

क्या आप कह रहे हैं कि इस मामले में, एक इकाई परीक्षण जो विधि की स्थिति को सत्यापित करता है वह पर्याप्त है? – JeremyWeir

+0

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

+0

@jayrdub - सामान्य राज्य सत्यापन में वही है जो आप अपने यूनिट परीक्षण करना चाहते हैं। परीक्षण के तहत विधि के/और या वस्तु के सार्वजनिक गुणों के वापसी मूल्य की जांच करें। बाकी सब कुछ एक कार्यान्वयन विस्तार है, और refactoring के दौरान बदल सकता है। – TrueWill

1

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

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

6

एक विधि है जो अपने आप को एक निश्चित शर्त के तहत कॉल, व्यवहार को सत्यापित करने के लिए एक परीक्षण लिखने के लिए यह संभव है?

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

वैसे भी, यहाँ उदाहरण यह कैसे परीक्षण करने के लिए अगर आप ऐसा नहीं कर सकते है। आपको वास्तव में किसी भी मॉकिंग की आवश्यकता नहीं है:

// Class under test 
public class Factorial 
{ 
    public virtual int Calculate(int number) 
    { 
     if (number < 2) 
      return 1 
     return Calculate(number-1) * number; 
    } 
} 

// The helper class to test the recursion 
public class FactorialTester : Factorial 
{ 
    public int NumberOfCalls { get; set; } 

    public override int Calculate(int number) 
    { 
     NumberOfCalls++; 
     return base.Calculate(number) 
    } 
}  

// Testing 
[Test] 
public void IsCalledAtLeastOnce() 
{ 
    var tester = new FactorialTester(); 
    tester.Calculate(1); 
    Assert.GreaterOrEqual(1, tester.NumberOfCalls ); 
} 
[Test] 
public void IsCalled3TimesForNumber3() 
{ 
    var tester = new FactorialTester(); 
    tester.Calculate(3); 
    Assert.AreEqual(3, tester.NumberOfCalls ); 
} 
4

आप नकली वस्तुओं के उद्देश्य को गलत समझ रहे हैं। मोक्स (मॉकिस्ट अर्थ में) परीक्षण के तहत सिस्टम की निर्भरताओं के साथ व्यवहारिक बातचीत का परीक्षण करने के लिए उपयोग किया जाता है।

interface IMailOrder 
{ 
    void OrderExplosives(); 
} 

class Coyote 
{ 
    public Coyote(IMailOrder mailOrder) {} 

    public void CatchDinner() {} 
} 

कोयोट IMailOrder पर निर्भर करता है:

तो, उदाहरण के लिए, आप कुछ इस तरह हो सकता है। उत्पादन कोड में, कोयोट का एक उदाहरण Acme का एक उदाहरण पारित किया जाएगा, जो IMailOrder लागू करता है। (यह मैनुअल निर्भरता इंजेक्शन के माध्यम से या एक डि ढांचे के माध्यम से किया जा सकता है।)

आप विधि CatchDinner का परीक्षण करने और सत्यापित करें कि यह OrderExplosives कॉल करना चाहते हैं।ऐसा करने के लिए, आप:

  1. नकली ऑब्जेक्ट बनाएं जो IMailOrder लागू करता है और अपने कन्स्ट्रक्टर को नकली ऑब्जेक्ट पास करके कोयोट (परीक्षण के तहत सिस्टम) का एक उदाहरण बनाएं। (व्यवस्थित करें)
  2. कॉल कैचडिनर। (अधिनियम)
  3. नकली ऑब्जेक्ट से यह सत्यापित करने के लिए कहें कि दी गई अपेक्षा (ऑर्डर एक्सप्लोज़िव्स) को पूरा किया गया था। (Assert)

जब आप नकली ऑब्जेक्ट पर अपेक्षाओं को सेट करते हैं तो आपके मॉकिंग (अलगाव) ढांचे पर निर्भर हो सकता है।

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

आप आमतौर पर सीमा की स्थिति का परीक्षण करना चाहते हैं, तो आप एक कॉल का परीक्षण कर सकते हैं जो रिकर्सिव नहीं होना चाहिए, एक रिकर्सिव कॉल के साथ कॉल, और एक गहराई से रिकर्सिव कॉल। (Miaubiz प्रत्यावर्तन, एक कार्यान्वयन विस्तार किया जा रहा है, हालांकि के बारे में एक अच्छा बिंदु है।)

संपादित करें: "कहते हैं" पिछले पैराग्राफ मैं मानकों के साथ एक फोन का मतलब या राज्य है कि किसी भी प्रत्यावर्तन गहराई को ट्रिगर करेगा वस्तु में रखकर। मैं The Art of Unit Testing पढ़ने की भी सिफारिश करता हूं।

संपादित करें 2: Moq का उपयोग कर उदाहरण परीक्षण कोड:

var mockMailOrder = new Mock<IMailOrder>(); 
var wily = new Coyote(mockMailOrder.Object); 

wily.CatchDinner(); 

mockMailOrder.Verify(x => x.OrderExplosives()); 
+0

"यदि आपके द्वारा परीक्षण की जाने वाली कक्षा या विधि में कोई बाहरी निर्भरता नहीं है, तो आपको परीक्षण के उस सेट के लिए नकली ऑब्जेक्ट्स का उपयोग करने की आवश्यकता नहीं है (इससे कोई फर्क नहीं पड़ता कि विधि रिकर्सिव है या नहीं।" यही वह हिस्सा है जिसे मुझे याद दिलाने की आवश्यकता है, धन्यवाद। मुझे आपका जवाब सबसे अच्छा लगा लेकिन यह करने से पहले यह स्वतः चुना गया। – JeremyWeir

+0

@jayrdub - धन्यवाद! :) – TrueWill

0

यहाँ मेरी 'किसान' दृष्टिकोण है

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

def factorial(n): 
    """Everyone knows this functions contract:) 
    Internally designed to use 'factorial_impl' (hence recursion).""" 
    return factorial_impl(n, factorial_impl) 

def factorial_impl(n, fct=factorial): 
    """This function's contract is 
    to return 'n*fct(n-1)' for n > 1, or '1' otherwise. 

    'fct' must be a function both taking and returning 'int'""" 
    return n*fct(n - 1) if n > 1 else 1 

परीक्षण:

कोड (मुख्य विचार एक भी लेकिन "untestable" पुनरावर्ती क्रिया से रिकर्सिवली निर्भर (और इस प्रकार परीक्षण योग्य) कार्यों का एक समान जोड़ी के लिए जाने के लिए है)

import unittest 

class TestFactorial(unittest.TestCase): 

    def test_impl(self): 
     """Test the 'factorial_impl' function, 
     'wiring' it to a specially constructed 'fct'""" 

     def fct(n): 
      """To be 'injected' 
      as a 'factorial_impl''s 'fct' parameter""" 
      # Use a simple number, which will 'show' itself 
      # in the 'factorial_impl' return value. 
      return 100 

     # Here we must get '1'. 
     self.assertEqual(factorial_impl(1, fct), 1) 
     # Here we must get 'n*100', note the ease of testing:) 
     self.assertEqual(factorial_impl(2, fct), 2*100) 
     self.assertEqual(factorial_impl(3, fct), 3*100) 

    def test(self): 
     """Test the 'factorial' function""" 
     self.assertEqual(factorial(1), 1) 
     self.assertEqual(factorial(2), 2) 
     self.assertEqual(factorial(3), 6) 

उत्पादन:

Finding files... 
['...py'] ... done 
Importing test modules ... done. 

Test the 'factorial' function ... ok 
Test the 'factorial_impl' function, ... ok 

---------------------------------------------------------------------- 
Ran 2 tests in 0.000s 

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