मैं मोक्स के साथ निम्नलिखित कोड का परीक्षण कैसे कर सकता हूं (मॉक का उपयोग करके, माइकल फ़ॉर्ड्स की रूपरेखा द्वारा पैच डेकोरेटर और प्रहरी ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
मैं मोक्स के साथ निम्नलिखित कोड का परीक्षण कैसे कर सकता हूं (मॉक का उपयोग करके, माइकल फ़ॉर्ड्स की रूपरेखा द्वारा पैच डेकोरेटर और प्रहरी ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
जवाबों:
इसे करने का तरीका मॉक 0.7.0 में बदल गया है जो अंत में पायथन प्रोटोकॉल विधियों (जादू के तरीकों) का समर्थन करता है, विशेष रूप से मैजिकमॉक का उपयोग करते हुए:
http://www.voidspace.org.uk/python/mock/magicmock.html
प्रसंग प्रबंधक के रूप में खुले हुए मॉकिंग का एक उदाहरण (नकली दस्तावेज़ में उदाहरण पृष्ठ से):
>>> open_name = '%s.open' % __name__
>>> with patch(open_name, create=True) as mock_open:
... mock_open.return_value = MagicMock(spec=file)
...
... with open('/some/path', 'w') as f:
... f.write('something')
...
<mock.Mock object at 0x...>
>>> file_handle = mock_open.return_value.__enter__.return_value
>>> file_handle.write.assert_called_with('something')
__enter__
और __exit__
साथ ही साथ वस्तुओं को नकली करने के लिए है - क्या उत्तरार्द्ध दृष्टिकोण पुराना है, या अभी भी उपयोगी है?
file
चला गया है!
mock_open
mock
फ्रेमवर्क का हिस्सा है और उपयोग करने के लिए बहुत सरल है। patch
संदर्भ के रूप में उपयोग किए गए ऑब्जेक्ट को पैच को बदलने के लिए उपयोग किया जाता है: आप इसका उपयोग अपने परीक्षण को सरल बनाने के लिए कर सकते हैं।
के builtins
बजाय का उपयोग करें __builtin__
।
from unittest.mock import patch, mock_open
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
mock
का हिस्सा नहीं है unittest
और आपको पैच करना चाहिए__builtin__
from mock import patch, mock_open
with patch("__builtin__.open", mock_open(read_data="data")) as mock_file:
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
यदि आप patch
डेकोरेटर के mock_open()
रूप में परिणाम के new
patch
तर्क के रूप में उपयोग करेंगे तो तर्क थोड़ा अजीब हो सकता है।
इस मामले में new_callable
patch
तर्क का उपयोग करना बेहतर है और याद रखें कि प्रत्येक अतिरिक्त तर्क जो patch
उपयोग नहीं new_callable
करता है, उसे patch
प्रलेखन में वर्णित कार्य करने के लिए पारित किया जाएगा ।
पैच () मनमाना कीवर्ड तर्क लेता है। इन्हें निर्माण पर मॉक (या new_callable) में पारित किया जाएगा।
उदाहरण के लिए पायथन 3.x के लिए सजाया गया संस्करण है:
@patch("builtins.open", new_callable=mock_open, read_data="data")
def test_patch(mock_file):
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
याद रखें कि इस मामले patch
में आप परीक्षण समारोह के तर्क के रूप में नकली वस्तु जोड़ देंगे।
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
डेकोरेटर सिंटैक्स में परिवर्तित किया जा सकता है? मैंने कोशिश की है, लेकिन मुझे यकीन नहीं है कि मुझे @patch("builtins.open", ...)
दूसरे तर्क के रूप में पारित करने की आवश्यकता है ।
return_value
की mock_open
एक और नकली वस्तु में और दूसरा नकली का ज़ोर return_value
), लेकिन यह जोड़ कर काम mock_open
के रूप में new_callable
।
six
लगातार mock
मॉड्यूल के लिए मॉड्यूल पर एक नज़र रखना । लेकिन मुझे नहीं पता कि यह builtins
एक सामान्य मॉड्यूल में भी है या नहीं।
नकली के नवीनतम संस्करणों के साथ, आप वास्तव में उपयोगी mock_open सहायक का उपयोग कर सकते हैं :
mock_open (नकली = कोई नहीं, read_data = कोई नहीं)
खुले के उपयोग को बदलने के लिए एक नकली बनाने के लिए एक सहायक कार्य करता है। यह खुले नाम से सीधे काम करता है या संदर्भ प्रबंधक के रूप में उपयोग किया जाता है।
मॉक तर्क कॉन्फ़िगर करने के लिए नकली वस्तु है। यदि कोई नहीं (डिफ़ॉल्ट) तो आपके लिए एक मैजिकमॉक बनाया जाएगा, जिसमें एपीआई मानक फ़ाइल हैंडल पर उपलब्ध विधियों या विशेषताओं तक सीमित है।
read_data फ़ाइल हैंडल के रीड मेथड के लिए एक स्ट्रिंग है जिसे वापस करना है। यह डिफ़ॉल्ट रूप से एक रिक्त स्ट्रिंग है।
>>> from mock import mock_open, patch
>>> m = mock_open()
>>> with patch('{}.open'.format(__name__), m, create=True):
... with open('foo', 'w') as h:
... h.write('some stuff')
>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')
.write
कॉल करते हैं, तो आप कैसे जांच करेंगे ?
handle.write.assert_any_call()
। handle.write.call_args_list
यदि ऑर्डर महत्वपूर्ण है तो आप प्रत्येक कॉल प्राप्त करने के लिए भी उपयोग कर सकते हैं ।
m.return_value.write.assert_called_once_with('some stuff')
बेहतर है इमो। कॉल रजिस्टर करने से बचा जाता है।
Mock.call_args_list
किसी भी Mock.assert_xxx
तरीके को कॉल करने की तुलना में मैन्युअल रूप से जोर देना सुरक्षित है । यदि आप मॉक की विशेषताओं में से किसी भी बाद में गलत वर्तनी करते हैं, तो वे हमेशा चुपचाप गुजरेंगे।
एक साधारण फ़ाइल के लिए mock_open का उपयोग करने के लिए read()
( इस पृष्ठ पर पहले से दिए गए मूल mock_open स्निपेट को लिखने के लिए अधिक तैयार किया गया है):
my_text = "some text to return when read() is called on the file object"
mocked_open_function = mock.mock_open(read_data=my_text)
with mock.patch("__builtin__.open", mocked_open_function):
with open("any_string") as f:
print f.read()
मॉक_पेन के लिए डॉक्स के अनुसार ध्यान दें, यह विशेष रूप से है read()
, इसलिए for line in f
उदाहरण के लिए सामान्य पैटर्न के साथ काम नहीं करेगा ।
अजगर 2.6.6 / नकली 1.0.1 का उपयोग करता है
for line in opened_file:
कोड के प्रकार के साथ काम नहीं कर सकता । मैंने पुनरावृत्ति करने वाले स्ट्रिंगरियो के साथ प्रयोग करने की कोशिश की, जो लागू होते हैं __iter__
और इसके बजाय इसका उपयोग करते हैं my_text
, लेकिन कोई भाग्य नहीं।
read()
से आपके for line in opened_file
मामले में काम नहीं करेगा के लिए काम करता है; मैंने पोस्ट को स्पष्ट करने के लिए संपादित किया है
for line in f:
समर्थन को इसके बजाय एक स्ट्रिंग ऑब्जेक्ट के open()
रूप में रिटर्न मान का मजाक उड़ाकर प्राप्त किया जा सकता है ।
with open("any_string") as f: print f.read()
शीर्ष उत्तर उपयोगी है, लेकिन मैंने इस पर थोड़ा विस्तार किया।
यदि आप अपने फ़ाइल ऑब्जेक्ट का मान सेट करना चाहते हैं, तो इसके लिए यहां दिए गए तर्कों के आधार पर ( f
इन as f
) open()
करें:
def save_arg_return_data(*args, **kwargs):
mm = MagicMock(spec=file)
mm.__enter__.return_value = do_something_with_data(*args, **kwargs)
return mm
m = MagicMock()
m.side_effect = save_arg_return_array_of_data
# if your open() call is in the file mymodule.animals
# use mymodule.animals as name_of_called_file
open_name = '%s.open' % name_of_called_file
with patch(open_name, m, create=True):
#do testing here
मूल रूप से, open()
किसी ऑब्जेक्ट को वापस करेगा और उस ऑब्जेक्ट पर with
कॉल करेगा __enter__()
।
ठीक से मॉक करने के लिए, हमें open()
मॉक ऑब्जेक्ट को वापस करने के लिए मॉक करना होगा । उस नकली वस्तु को उसके बाद उस __enter__()
कॉल को मॉक करना चाहिए ( MagicMock
जो हमारे लिए यह करेगा) उस नकली डेटा / फ़ाइल ऑब्जेक्ट को वापस करना होगा जिसे हम चाहते हैं (इसलिए mm.__enter__.return_value
)। ऐसा करने से 2 मोक्स ऊपर के रास्ते से open()
गुजरते हैं, जिससे हम पास किए गए तर्कों को कैप्चर कर सकते हैं और उन्हें हमारे do_something_with_data
तरीके से पास कर सकते हैं ।
मैंने एक स्ट्रिंग के रूप में एक पूरी मॉक फाइल पास की open()
और मुझे do_something_with_data
इस तरह देखा:
def do_something_with_data(*args, **kwargs):
return args[0].split("\n")
यह स्ट्रिंग को एक सूची में बदल देता है ताकि आप एक सामान्य फ़ाइल के साथ निम्न कार्य कर सकें:
for line in file:
#do action
__enter__
? यह निश्चित रूप से एक अनुशंसित तरीके से हैक की तरह दिखता है।
मुझे खेल में थोड़ी देर हो सकती है, लेकिन यह मेरे लिए तब काम करता है जब open
एक नई फ़ाइल बनाने के बिना दूसरे मॉड्यूल में कॉल किया जाता है।
test.py
import unittest
from mock import Mock, patch, mock_open
from MyObj import MyObj
class TestObj(unittest.TestCase):
open_ = mock_open()
with patch.object(__builtin__, "open", open_):
ref = MyObj()
ref.save("myfile.txt")
assert open_.call_args_list == [call("myfile.txt", "wb")]
MyObj.py
class MyObj(object):
def save(self, filename):
with open(filename, "wb") as f:
f.write("sample text")
मेरे open
अंदर __builtin__
मॉड्यूल के अंदर फ़ंक्शन को पैच करके mock_open()
, मैं बिना किसी को बनाए किसी फाइल को लिखने का मजाक उड़ा सकता हूं।
नोट: यदि आप एक ऐसे मॉड्यूल का उपयोग कर रहे हैं जो साइथॉन का उपयोग करता है, या आपका प्रोग्राम किसी भी तरह से साइथन पर निर्भर करता है, तो आपको अपनी फ़ाइल के शीर्ष पर शामिल करके साइथन के __builtin__
मॉड्यूल को आयात करना होगा import __builtin__
। __builtin__
यदि आप साइथन का उपयोग कर रहे हैं तो आप सार्वभौमिक का मजाक नहीं उड़ा पाएंगे।
import __builtin__
अपने परीक्षण मॉड्यूल में जोड़ना सुनिश्चित करने की आवश्यकता थी । इस लेख ने यह स्पष्ट करने में मदद की कि यह तकनीक क्यों काम करती है: ichimonji10.name/blog/6
यह एक पैच के लिए एक जॉन्सन कॉन्फिगर पढ़ने के लिए काम करता है।
class ObjectUnderTest:
def __init__(self, filename: str):
with open(filename, 'r') as f:
dict_content = json.load(f)
मॉक की गई वस्तु io.TextIOWrapper ऑब्जेक्ट ओपन () फ़ंक्शन द्वारा लौटाई गई है
@patch("<src.where.object.is.used>.open",
return_value=io.TextIOWrapper(io.BufferedReader(io.BytesIO(b'{"test_key": "test_value"}'))))
def test_object_function_under_test(self, mocker):
यदि आपको आगे किसी फ़ाइल की आवश्यकता नहीं है, तो आप परीक्षण विधि को सजा सकते हैं:
@patch('builtins.open', mock_open(read_data="data"))
def test_testme():
result = testeme()
assert result == "data"