2015-07-09 10 views
8

मान लीजिए कि प्रोजेक्ट में दो पैकेज हैं: some_package और another_packageपायटेस्ट बंदरपैच आयातित फ़ंक्शन पर काम नहीं कर रहा है

# some_package/foo.py: 
def bar(): 
    print('hello') 

# another_package/function.py 
from some_package.foo import bar 

def call_bar(): 
    # ... code ... 
    bar() 
    # ... code ... 

मैं some_package.foo.bar बाहर मजाक है क्योंकि यह कुछ नेटवर्क आई/ओ मैं बचना चाहते है another_package.function.call_bar परीक्षण करना चाहते हैं।

# tests/test_bar.py 
from another_package.function import call_bar 

def test_bar(monkeypatch): 
    monkeypatch.setattr('some_package.foo.bar', lambda: print('patched')) 
    call_bar() 
    assert True 

मेरे आश्चर्य करने के लिए यह आउटपुट hello बजाय mock:

यहाँ एक परीक्षण है। मैंने परीक्षण में आईपीडीबी ब्रेकपॉइंट डालने से इस चीज़ को डीबग करने की कोशिश की। जब मैं ब्रेकपॉइंट के बाद some_package.foo.bar मैन्युअल रूप से आयात करता हूं और bar() पर कॉल करता हूं तो मुझे patched मिलता है।

मेरी वास्तविक परियोजना पर स्थिति और भी दिलचस्प है। अगर मैं प्रोजेक्ट रूट में pytest का आह्वान करता हूं तो मेरा फ़ंक्शन पैच नहीं होता है, लेकिन जब मैं tests/test_bar.py को तर्क के रूप में निर्दिष्ट करता हूं - यह काम करता है।

जहां तक ​​मुझे लगता है कि from some_package.foo import bar कथन के साथ इसका कुछ संबंध है। यदि बंदरगाहिंग होने से पहले इसे निष्पादित किया जा रहा है तो यह पैचिंग विफल हो जाती है। लेकिन ऊपर पैचिंग के उदाहरण से संघीय परीक्षण सेटअप पर दोनों मामलों में काम नहीं करता है।

और यह ब्रेकपॉइंट मारने के बाद आईपीडीबी आरपीएल में क्यों काम करता है?

उत्तर

6

आयात नाम है, वस्तु के लिए एक नया नाम बनाता है, तो आप तो पुराने नाम वस्तु के लिए नया नाम अप्रभावित

मॉड्यूल आयात और बजाय module.bar का उपयोग है, कि हमेशा वर्तमान वस्तु का उपयोग करेगा की जगह

संपादित करें:

import module 

def func_under_test(): 
    module.foo() 


def test_func(): 
    monkeypatch.setattr(...) 
    func_under_test 
+4

यह सबसे ज्यादा गेटचास में से एक है - लेकिन इसे समझाने के लिए धन्यवाद। –

+0

जब आप "मॉड्यूल.बार का उपयोग करें" कहते हैं, तो क्या आप एक कोड उदाहरण प्रदान कर सकते हैं? मैंने 'monkeypatch.setattr (मॉड्यूल, 'बार', mock_obj)' और सफलता के बिना कुछ अन्य incantations की कोशिश की है। – skolsuper

+0

आपके उत्तर के लिए धन्यवाद। क्या यह सुनिश्चित करने के लिए कोई चाल है कि कोई भी आयात मॉक ऑब्जेक्ट का उपयोग करेगा। क्योंकि अब के लिए यह खतरनाक है, उदाहरण के लिए, मैं – Stavinsky

1

जबकि Ronny's answer यह आप बलों आवेदन कोड को बदलने के लिए काम करता है। सामान्य रूप से आपको परीक्षण के लिए ऐसा नहीं करना चाहिए।

इसके बजाय आप ऑब्जेक्ट को दूसरे पैकेज में स्पष्ट रूप से पैच कर सकते हैं। इसका उल्लेख docs for the unittest module में किया गया है।

monkeypatch.setattr('another_package.bar', lambda: print('patched')) 
संबंधित मुद्दे