2008-10-07 14 views
12

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

उदाहरण के रूप में: जिन कार्यों को मैं परीक्षण करना चाहता हूं, उनके साथ फ़ाइल, दस अन्य फाइलों को आयात करती है जो हमारे सॉफ़्टवेयर का हिस्सा हैं और पायथन कोर libs नहीं।

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

सभी उत्तरों के लिए धन्यवाद।

मुझे वास्तव में पता नहीं था कि मैं शुरुआत से क्या करना चाहता था लेकिन अब मुझे लगता है कि मुझे पता है।

समस्या यह थी कि कुछ आयात केवल तभी संभव था जब पूरा एप्लिकेशन कुछ तीसरे पक्ष के ऑटो-जादू के कारण चल रहा था। तो मुझे एक निर्देशिका में इन मॉड्यूल के लिए कुछ स्टब्स बनाना पड़ा, जिसमें मैंने sys.path

अब फाइल आयात कर सकते हैं जिसमें मैं अपने यूनिट-टेस्ट फ़ाइल में परीक्षण लिखना चाहता हूं, बिना किसी शिकायत के गायब मॉड्यूल।

उत्तर

7

यदि आप एक मॉड्यूल आयात करना चाहते हैं, जबकि यह सुनिश्चित करते हुए कि यह कुछ भी आयात नहीं करता है, तो आप __import__ बिल्टिन फ़ंक्शन को प्रतिस्थापित कर सकते हैं।

उदाहरण के लिए, इस वर्ग का उपयोग करें:

class ImportWrapper(object): 
    def __init__(self, real_import): 
     self.real_import = real_import 

    def wrapper(self, wantedModules): 
     def inner(moduleName, *args, **kwargs): 
      if moduleName in wantedModules: 
       print "IMPORTING MODULE", moduleName 
       self.real_import(*args, **kwargs) 
      else: 
       print "NOT IMPORTING MODULE", moduleName 
     return inner 

    def mock_import(self, moduleName, wantedModules): 
     __builtins__.__import__ = self.wrapper(wantedModules) 
     try: 
      __import__(moduleName, globals(), locals(), [], -1) 
     finally: 
      __builtins__.__import__ = self.real_import 

और अपने परीक्षण कोड में, बजाय import myModule लिखने की, लिखें:

wrapper = ImportWrapper(__import__) 
wrapper.mock_import('myModule', []) 

mock_import को दूसरा तर्क मॉड्यूल नाम आप की एक सूची है आंतरिक मॉड्यूल में आयात करना चाहते हैं।

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

+0

आप mock_import विधि पर 'try: end:' को जोड़ना चाहते हैं, त्रुटि – Yonatan

+0

@Yonatan के मामले में डिफॉल्ट एक के बजाय सिस्टम को लपेटने के आयात से बचने के लिए: आप सही हैं, धन्यवाद! मैंने अपना कोड संशोधित किया। – DzinX

1

"कई अन्य फाइलों का आयात करता है"? कई अन्य फाइलों का आयात करता है जो आपके अनुकूलित कोड बेस का हिस्सा हैं? या पाइथन वितरण का हिस्सा हैं जो कई अन्य फाइलों का आयात करता है? या कई अन्य ओपन सोर्स प्रोजेक्ट फाइलों का आयात करता है?

यदि आपके आयात काम नहीं करते हैं, तो आपके पास "सरल" PYTHONPAT एच समस्या है। अपनी सभी विभिन्न परियोजना निर्देशिकाओं को PYTHONPATH पर प्राप्त करें जिन्हें आप परीक्षण के लिए उपयोग कर सकते हैं। हम एक नहीं बल्कि जटिल पथ है, Windows में हम इसे इस

@set Part1=c:\blah\blah\blah 
@set Part2=c:\some\other\path 
@set that=g:\shared\stuff 
set PYTHONPATH=%part1%;%part2%;%that% 

तरह का प्रबंधन हम पथ के प्रत्येक टुकड़े को अलग रखने ताकि हम (क) पता है जहां चीजें से आते हैं और (ख) परिवर्तन प्रबंधन कर सकते हैं जब हम ले जाने के चीजें चारों ओर।

चूंकि PYTHONPATH खोज में है, इसलिए हम पथ पर ऑर्डर समायोजित करके उपयोग किए जाने वाले कार्यों को नियंत्रित कर सकते हैं।

एक बार जब आपके पास "सब कुछ" हो, तो यह विश्वास का सवाल बन जाता है।

या तो

  • आप कुछ (जैसे कि, पायथन कोड आधार) पर विश्वास है और इसे आयात करते हैं।

या

  • तुम कुछ (जैसे कि, अपने खुद के कोड) और आप

    1. परीक्षण इसे अलग से और
    2. स्टैंड-अलोन परीक्षण के लिए यह नकली पर भरोसा नहीं करते।

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

1

यदि आप वास्तव में पाइथन आयात तंत्र के साथ मिलना चाहते हैं, तो ihooks मॉड्यूल पर एक नज़र डालें। यह अंतर्निहित __import__ के व्यवहार को बदलने के लिए टूल प्रदान करता है। लेकिन यह आपके प्रश्न से स्पष्ट नहीं है कि आपको ऐसा करने की आवश्यकता क्यों है।

0

यदि आप अपने यूनिट-टेस्ट से पहले त्वरित और गंदे फिक्स चाहते हैं तो कोई मुश्किल हेरफेर आवश्यक नहीं है।

यदि यूनिट परीक्षण उसी कोड में हैं, जिस कोड को आप परीक्षण करना चाहते हैं, तो globals() शब्दकोश से अवांछित मॉड्यूल को हटाएं।

यहाँ एक नहीं बल्कि लंबा उदाहरण है: मान लीजिए कि आप सामग्री के साथ एक मॉड्यूल impp.py है:

value = 5 

अब, अपने परीक्षण फ़ाइल में आप लिख सकते हैं:

>>> import impp 
>>> print globals().keys() 
>>> def printVal(): 
>>>  print impp.value 
['printVal', '__builtins__', '__file__', 'impp', '__name__', '__doc__'] 

ध्यान दें कि impp में से एक है globals, क्योंकि यह आयात किया गया था। समारोह printValimpp मॉड्यूल अभी भी उपयोग करता है कॉलिंग काम करता है:

>>> printVal() 
5 

लेकिन अब, अगर आप globals() से impp कुंजी ...

>>> del globals()['impp'] 
>>> print globals().keys() 
['printVal', '__builtins__', '__file__', '__name__', '__doc__'] 

हटाने ... और printVal() कॉल करने के लिए प्रयास करते हैं, आप करेंगे प्राप्त करें:

>>> printVal() 
Traceback (most recent call last): 
    File "test_imp.py", line 13, in <module> 
    printVal() 
    File "test_imp.py", line 5, in printVal 
    print impp.value 
NameError: global name 'impp' is not defined 

... जो शायद आप प्राप्त करने की कोशिश कर रहे हैं।

अपने यूनिट-परीक्षणों में इसका उपयोग करने के लिए, आप टेस्ट सूट चलाने से पहले ग्लोबल्स को हटा सकते हैं, उदा। __main__ में:

if __name__ == '__main__': 
    del globals()['impp'] 
    unittest.main() 
+0

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

0

अपनी टिप्पणी above में, आप कहते हैं कि तुम अजगर है कि कुछ मॉड्यूल पहले से ही आयात किया गया है समझाने के लिए चाहते हैं। यह अभी भी एक अजीब लक्ष्य की तरह प्रतीत होता है, लेकिन यदि आप वास्तव में क्या करना चाहते हैं, तो सिद्धांत रूप में आप आयात तंत्र की पीठ के पीछे घूम सकते हैं, और sys.modules बदल सकते हैं। यह सुनिश्चित नहीं है कि यह पैकेज आयात के लिए कैसे काम करेगा, लेकिन पूर्ण आयात के लिए ठीक होना चाहिए।

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