বিবৃতি সহ (পাইথনের মক ফ্রেমওয়ার্কটি ব্যবহার করে) কীভাবে খোলা ব্যাবহার করব?


188

আমি কীভাবে নীচের কোডটিকে মক (টেবিলে, প্যাচ ডেকোরেটর এবং মাইকেল ফোর্ডের মক ফ্রেমওয়ার্ক দ্বারা সরবরাহিত সেন্ডিনেল ব্যবহার করে ) পরীক্ষা করব?

def testme(filepath):
    with open(filepath, 'r') as f:
        return f.read()

@ ড্যারিল স্পিজিটর: আপনি কী মেটা-প্রশ্ন ছেড়ে দিতে পারেন ("আমি উত্তরটি জানি ...") এটি বিভ্রান্তিকর।
এস .লট

অতীতে যখন আমি এটি ছেড়ে দিয়েছি, লোকেরা অভিযোগ করেছে যে আমি আমার নিজের প্রশ্নের উত্তর দিচ্ছি। আমি আমার উত্তরে এটি সরানোর চেষ্টা করব।
ড্যারিল স্পিজিটর

1
@ ড্যারিল: নিজের প্রশ্নের উত্তর সম্পর্কে অভিযোগগুলি এড়ানোর সর্বোত্তম উপায়, যা সাধারণত "কর্মফল" হিসাবে উদ্বেগ থেকে উদ্ভূত হয়, তা হল প্রশ্ন এবং / অথবা উত্তরটিকে "সম্প্রদায়ের উইকি" হিসাবে চিহ্নিত করা।
জন মিলিকিন

3
যদি আপনার নিজের প্রশ্নের উত্তরকে কর্ম ভর্য়িং হিসাবে বিবেচনা করা হয়, তবে আমার মনে হয় সেই প্রশ্নে এফএকিউ পরিষ্কার করা উচিত।
ইবিগ্রিন

উত্তর:


131

এটি করার উপায়টি মক ০..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')

কি দারুন! এটি বর্তমানে voidspace.org.uk/python/mock/magicmock.html এ প্রসঙ্গ-পরিচালকের উদাহরণের চেয়ে অনেক সহজ দেখায় যা স্পষ্টতই সেট করে __enter__এবং __exit__বস্তুগুলিকে বিদ্রূপ করার জন্য - পরবর্তী উত্তরটি কি পুরানো , নাকি এখনও কার্যকর?
ব্র্যান্ডন রোডস

5
"আধুনিক অভিগমন" এটা কিভাবে দেখানো হয় ছাড়া একটি MagicMock (অর্থাত এটা ঠিক কিভাবে নকল যাদু পদ্ধতি সমর্থন একটি উদাহরণ) ব্যবহার করে। আপনি যদি কোনও ম্যাজিকমক ব্যবহার করেন (উপরে হিসাবে) তবে প্রবেশ করুন এবং প্রস্থান আপনার জন্য পূর্বনির্ধারিত।
ফিজিম্যান

5
আপনি আপনার ব্লগ পোস্টের দিকে ইঙ্গিত করতে পারেন যেখানে আপনি কেন / কীভাবে কাজ করে তার আরও বিশদে ব্যাখ্যা করেছেন
রডরিগ

9
পাইথন 3-তে, 'ফাইল' সংজ্ঞায়িত করা হয়নি (ম্যাজিকমোক স্পেসে ব্যবহৃত), সুতরাং আমি এর পরিবর্তে io.IOBase ব্যবহার করছি।
জোনাথন হার্টলি

1
দ্রষ্টব্য: পাইথন 3 এ বিল্টিনটি fileগেছে!
exhuma

239

mock_openmockকাঠামোর অংশ এবং এটি ব্যবহার করা খুব সহজ। patchপ্রসঙ্গ হিসাবে ব্যবহৃত প্যাচযুক্ত প্রতিস্থাপন করতে ব্যবহৃত বস্তুটি ফেরত দেয়: আপনি এটি পরীক্ষা সহজতর করতে এটি ব্যবহার করতে পারেন।

পাইথন 3.x

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")

পাইথন 2.7

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

প্যাচ () নির্বিচারে কীওয়ার্ড আর্গুমেন্ট নেয়। এগুলি নির্মাণের জন্য মোক (বা নতুন_আপনযোগ্য) এ পাঠানো হবে।

উদাহরণস্বরূপ পাইথন ৩.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", ...) দ্বিতীয় তর্ক হিসাবে আমার কী দরকার তা আমি নিশ্চিত নই ।
imrek

1
@ ড্রঙ্কনমাস্টার আপডেট হয়েছে .. এটি উল্লেখ করার জন্য ধন্যবাদ। সজ্জা ব্যবহারকারীর ব্যবহার এই ক্ষেত্রে তুচ্ছ নয়।
মিশেল ডি'আমিকো

Grazie! আমার সমস্যা একটু বেশি জটিল ছিল (আমি চ্যানেলের ছিল return_valueএর mock_openঅন্য উপহাস বস্তুর মধ্যে এবং দ্বিতীয় উপহাস এর জাহির return_value), কিন্তু এটি যোগ করে কাজ mock_openযেমন new_callable
imrek

1
sixসামঞ্জস্যপূর্ণ mockমডিউল পেতে আর্থারজপেলোরো মডিউলটিতে একবার নজর দিন । তবে আমি জানি না এটি builtinsকোনও সাধারণ মডিউলটিতেও ম্যাপ করে ।
মিশেল ডি'আমিকো

1
আপনি প্যাচ করার সঠিক নামটি কীভাবে খুঁজে পাবেন? অর্থাত্ আপনি কীভাবে কোনও সালিশী ফাংশনের জন্য @ প্যাচ ('বিল্টিনস.ওপেন') এর প্রথম যুক্তিটি খুঁজে পাবেন?
zenperttu

73

মকের সর্বশেষতম সংস্করণগুলি সহ, আপনি সত্যিই দরকারী মক_পেন সহায়তা ব্যবহার করতে পারেন :

মক_পেন (উপহাস = কিছুই নয়, পঠিত_ডাটা = কোনওটি নয়)

খোলা ব্যবহার প্রতিস্থাপনের জন্য একটি উপকারী তৈরি করার জন্য একটি সহায়ক ফাংশন। এটি সরাসরি ডাকা বা কনটেক্সট ম্যানেজার হিসাবে ব্যবহৃত ওপেনের জন্য কাজ করে।

মক আর্গুমেন্টটি কনফিগার করার জন্য মক অবজেক্ট। যদি কিছুই না (ডিফল্ট) থাকে তবে স্ট্যান্ডার্ড ফাইল হ্যান্ডলগুলিতে উপলব্ধ পদ্ধতি বা বৈশিষ্ট্যগুলিতে সীমাবদ্ধ থাকা এপিআই দিয়ে আপনার জন্য একটি ম্যাজিকমক তৈরি করা হবে।

রিড_ডেটা ফাইল হ্যান্ডেলটি ফেরত পাঠানোর পদ্ধতির জন্য একটি স্ট্রিং। এটি ডিফল্টরূপে একটি খালি স্ট্রিং।

>>> 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কল আছে কিনা তা আপনি কীভাবে পরীক্ষা করবেন ?
n611x007

1
@naxa এক উপায় হ'ল প্রতিটি প্রত্যাশিত প্যারামিটারটি পাস করা handle.write.assert_any_call()handle.write.call_args_listঅর্ডারটি গুরুত্বপূর্ণ হলে আপনি প্রতিটি কল পেতে ব্যবহার করতে পারেন।
রব কাটমোর

m.return_value.write.assert_called_once_with('some stuff')ভাল ইমো। কল নিবন্ধন করা এড়ানো।
বেনামে

2
ম্যানুয়ালি সম্পর্কে জোর দেওয়া , পদ্ধতিগুলির Mock.call_args_listযে কোনওটিকে কল করার চেয়ে নিরাপদ Mock.assert_xxx। আপনি যদি পরেরটি, মকের বৈশিষ্ট্য হিসাবে ভুল বানান করে থাকেন তবে সে সর্বদা নীরবে পাস করবে pass
জোনাথন হার্টলি

12

একটি সাধারণ ফাইলের জন্য মক_পেন ব্যবহার করতে read()( এই পৃষ্ঠায় ইতিমধ্যে প্রদত্ত আসল মক_পেন স্নিপেটটি লেখার জন্য আরও প্রস্তুত করা হয়েছে):

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 / উপহাস 1.0.1 ব্যবহার করে


দেখতে দেখতে দুর্দান্ত লাগছে, তবে for line in opened_file:কোডের ধরণের সাহায্যে আমি এটি পেতে পারি না । আমি পুনরাবৃত্তিযোগ্য স্ট্রিংআইওর সাথে পরীক্ষার চেষ্টা করেছি যা প্রয়োগ করে __iter__এবং এর পরিবর্তে এটি ব্যবহার করে my_text, তবে ভাগ্য নেই।
ইভজেন

@ এভেজেনি পুচাকারিভ এটি বিশেষভাবে কাজ করে read()তাই এটি আপনার for line in opened_fileক্ষেত্রে কাজ করবে না ; আমি স্পষ্ট করতে পোস্টটি সম্পাদনা করেছি
jlb83

1
@EvgeniiPuchkaryov for line in f:সমর্থন ফেরত মান উপহাস অর্জন করা সম্ভব open()হিসাবে একটি StringIO পরিবর্তে আপত্তি
ইসকার জারাক

1
স্পষ্ট করার জন্য, এই উদাহরণে পরীক্ষার অধীনে সিস্টেম (এসইউটি) হ'ল: with open("any_string") as f: print f.read()
ব্র্যাড এম

4

শীর্ষের উত্তরটি দরকারী তবে আমি এটির উপরে কিছুটা প্রসারিত করেছি।

আপনি যদি এখানে যাবেন তার একটি উপায় দিয়ে যুক্তিগুলির ভিত্তিতে আপনার ফাইল অবজেক্টের ( 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

যদি পরীক্ষিত কোডটি ফাইলটিকে অন্যভাবে পরিচালনা করে, উদাহরণস্বরূপ এর ফাংশনটিকে "রিডলাইন" বলার মাধ্যমে আপনি "do_something_with_data" ফাংশনটিতে যে কোনও মক অবজেক্টটি পছন্দসই বৈশিষ্ট্য সহ ফিরিয়ে দিতে পারেন।
ব্যবহারকারী 3289695

স্পর্শ এড়ানোর কোনও উপায় আছে __enter__? এটি অবশ্যই প্রস্তাবিত উপায়ের চেয়ে হ্যাকের মতো দেখতে আরও বেশি লাগে।
imrek

প্রবেশ কিভাবে খোলা মত conext পরিচালকদের () লিখিত হয়। ঠাট্টা করে প্রায়ই যে অ্যাক্সেস করতে উপহাস "ব্যক্তিগত" জিনিস প্রয়োজন একটি বিট হল hacky হবে, কিন্তু এখানে নয ingerintly হল hacky নিচ প্রবেশ
theannouncer

3

গেমটি হতে আমি কিছুটা দেরি করতে পারি, তবে কল করার সময় এটি আমার পক্ষে কাজ করে 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__আমার পরীক্ষার মডিউলটি যুক্ত করার জন্য আমার নিশ্চিত করা দরকার ছিল । এই নিবন্ধটি কেন এই কৌশলটি যেমন কাজ করে তেমনি এটিও
21th15

0

ইউনিটেস্টের সাথে বিল্ট-ইন ওপেন () ফাংশনটি প্যাচ করতে:

এটি একটি প্যাচগুলির জন্য একটি জসন কনফিগারেশন পড়ার জন্য কাজ করেছিল।

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):

0

আপনার যদি আর কোনও ফাইলের প্রয়োজন না হয় তবে আপনি পরীক্ষা পদ্ধতিটি সাজাইতে পারেন:

@patch('builtins.open', mock_open(read_data="data"))
def test_testme():
    result = testeme()
    assert result == "data"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.