كيف يمكنني أن أسخر منفتحا مستخدما في بيان (باستخدام إطار عمل وهمية في بيثون)؟

StackOverflow https://stackoverflow.com/questions/1289894

  •  18-09-2019
  •  | 
  •  

سؤال

كيف يمكنني اختبار التعليمة البرمجية التالية باستخدام أسخر (باستخدام الأسخر، الديكور التصحيح والحرارة المقدمة من قبل إطار وهمية ميكايل فوورد):

def testme(filepath):
    with open(filepath, 'r') as f:
        return f.read()
هل كانت مفيدة؟

المحلول

لقد تغيرت طريقة القيام بذلك في MOCK 0.7.0 والتي تدعم أخيرا يسخر من أساليب بروتوكول Python (الأساليب السحرية)، خاصة باستخدام MagicMock:

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

نصائح أخرى

هناك الكثير من الضوضاء في هذه الإجابات؛ كل شيء تقريبا صحيح ولكن قديم وليس أنيقا. mock_open هو جزء من mock الإطار وهو بسيط جدا للاستخدام. 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 كما decorator باستخدام mock_open()النتيجة كما new patchيمكن أن تكون حجة غريبة بعض الشيء.

في هذه الحالة أفضل استخدام new_callable patchحجة وتذكر أن كل حجج إضافية patch لا يستخدم سيتم تمريره إلى new_callable وظيفة كما هو موضح في patch توثيق.

التصحيح () يأخذ وسيطات الكلمات الرئيسية التعسفية. سيتم تمرير هذه إلى الفحص (أو New_Calable) على البناء.

على سبيل المثال نسخة مزينة ل بيثون 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 سيضيف كائن وهمية كحجة لوظيفة اختبار لك.

مع أحدث إصدارات MOCK، يمكنك استخدام مفيدة حقا mock_open. المساعد:

mock_open (وهمية = لا شيء، read_data = none)

وظيفة المساعد لإنشاء وهمية لاستبدال استخدام فتح. إنه يعمل لفتح يسمى مباشرة أو يستخدم كمدير سياق.

وسيطة وهمية هي كائن وهمية لتكوينه. إذا لم يكن أي منها (الافتراضي)، فسيتم إنشاء MagicMock من أجلك، حيث تقتصر API على الأساليب أو السمات المتوفرة على مقابض الملفات القياسية.

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

ليستخدم 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()

ملاحظة حسب مستندات mock_open، هذا على وجه التحديد read(), لذلك لن تعمل مع أنماط شائعة مثل for line in f, ، علي سبيل المثال.

يستخدم Python 2.6.6 / Mock 1.0.1

قد أكون متأخرا بعض الشيء مع اللعبة، لكن هذا عملت من أجلي عند الاتصال 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(), ، يمكنني أن أسخر الكتابة إلى ملف دون إنشاء واحد.

ملاحظة: إذا كنت تستخدم وحدة نمطية تستخدم Cython، أو يعتمد برنامجك على سيلون بأي شكل من الأشكال، فستحتاج إلى استيراد سينثون __builtin__ وحدة عن طريق شمل import __builtin__ في الجزء العلوي من الملف الخاص بك. لن تكون قادرة على وهمية العالمي __builtin__ إذا كنت تستخدم سيلون.

الجواب الأعلى مفيد لكني توسيعت عليه قليلا.

إذا كنت ترغب في تعيين قيمة كائن الملف الخاص بك ( 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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top