মোক দিয়ে পঠনযোগ্য সম্পত্তি কীভাবে উপহাস করবেন?


92

আপনি কীভাবে মোক নিয়ে পঠনযোগ্য সম্পত্তিকে উপহাস করবেন ?

আমি চেষ্টা করেছিলাম:

setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())

তবে বিষয়টি হ'ল এটি তখন ক্লাসের সমস্ত ক্ষেত্রে প্রয়োগ হয় ... যা আমার পরীক্ষাগুলি ভঙ্গ করে।

আপনার কি অন্য কোনও ধারণা আছে? আমি পুরো অবজেক্টকে বিদ্রূপ করতে চাই না, কেবল এই নির্দিষ্ট সম্পত্তি।

উত্তর:


167

আমি মনে করি আরও ভাল উপায় হ'ল সম্পত্তিটিকে উপহাস করার PropertyMockপরিবর্তে __get__পদ্ধতিটি সরাসরি উপহাস করার চেয়ে ।

এটি ডকুমেন্টেশনে বর্ণিত হয়েছে , এর জন্য অনুসন্ধান করুন unittest.mock.PropertyMock: একটি শ্রেণিটিতে সম্পত্তি বা অন্য বর্ণনাকারী হিসাবে ব্যবহার করার উদ্দেশ্যে তৈরি একটি উপহাস। PropertyMockসরবরাহ করে __get__এবং __set__পদ্ধতিগুলি যাতে আপনি আনার সময় কোনও রিটার্ন মান নির্দিষ্ট করতে পারেন।

এটি এখানে:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

def test(unittest.TestCase):
    with mock.patch('MyClass.last_transaction', new_callable=PropertyMock) as mock_last_transaction:
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()

আমি যেমন একটি সজ্জিত একটি শ্রেণি পদ্ধতি উপহাস করতে হয়েছিল @property। এই উত্তরটি আমার পক্ষে কাজ করেছিল যখন অন্যান্য উত্তর (এবং অন্যান্য অনেক প্রশ্নের অন্যান্য উত্তর) না দেয়।
অ্যালানসই

4
এইভাবে এটি করা উচিত। আমি আশা করি "গ্রহণযোগ্য" উত্তরটি সরিয়ে দেওয়ার কোনও উপায়
থাকত

4
সামান্য পরিচ্ছন্ন হওয়ার প্রসঙ্গে ম্যানেজার কলটিতে আমি রিটার্নের মানটি সহ পেয়েছি: ock `m mock.patch সহ ('MyClass.last_transaction', new_clalable = PropertiesMock, return_value = Transferences ()): ...` ``
ওয়ডো

প্রকৃতপক্ষে, আমি কেবলমাত্র এইটির গৃহীত উত্তরটি সরিয়ে নিয়েছি।
চার্লাক্স

4
mock.patch.object ব্যবহার করাও দুর্দান্ত কারণ যেহেতু আপনাকে ক্লাসের নামটি স্ট্রিং হিসাবে লিখতে হবে না (উদাহরণের মধ্যে আসলেই কোনও সমস্যা নয়) এবং আপনি যদি কোনও প্যাকেজটির নাম পরিবর্তন করার সিদ্ধান্ত নেন এবং না করে থাকেন তবে এটি সনাক্ত / ঠিক করা সহজ easier একটি পরীক্ষা আপডেট করেছেন
কেভিন

41

প্রকৃতপক্ষে, ডকুমেন্টেশনের উত্তরটি (যথারীতি) ছিল, আমি যখন ক্লাসের পরিবর্তে উদাহরণটি প্যাচটি প্রয়োগ করছিলাম তখন আমি তাদের উদাহরণ অনুসরণ করি।

কিভাবে করতে হবে এখানে আছে:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

পরীক্ষার স্যুটটিতে:

def test():
    # Make sure you patch on MyClass, not on a MyClass instance, otherwise
    # you'll get an AttributeError, because mock is using settattr and
    # last_transaction is a readonly property so there's no setter.
    with mock.patch(MyClass, 'last_transaction') as mock_last_transaction:
        mock_last_transaction.__get__ = mock.Mock(return_value=Transaction())
        myclass = MyClass()
        print myclass.last_transaction

14
লোকদের অন্য উদাহরণ ব্যবহার করা উচিত। mock.PropertyMockএটা কি উপায়!
ভাইরাসটি

4
এটি সঠিক, লেখার সময় PropertyMockউপস্থিত ছিল না।
চার্লাক্স

6

আপনি যে জিনিসটির সম্পত্তিটি ওভাররাইড করতে চান সেটি যদি একটি উপহাস বস্তু হয় তবে আপনাকে ব্যবহার করতে হবে না patch

পরিবর্তে, তৈরি করতে পারেন PropertyMockএবং তারপর সম্পত্তি ওভাররাইড টাইপ উপহাস করে। উদাহরণস্বরূপ, mock_rows.pagesফেরত দেওয়ার জন্য সম্পত্তিটিকে ওভাররাইড করা (mock_page, mock_page,):

mock_page = mock.create_autospec(reader.ReadRowsPage)
# TODO: set up mock_page.
mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,))
type(mock_rows).pages = mock_pages

4
বাম, ঠিক আমি যা চাইছিলাম (কোনও সম্পত্তির সাথে অটোস্পেক করা হবে)। এবং কোনও সহকর্মীর থেকে কম 🙋‍♂️
মার্ক ম্যাকডোনাল্ড

6

সম্ভবত শৈলীর বিষয় তবে আপনি পরীক্ষাগুলিতে সজ্জা পছন্দ করলে, @ জামেসেস্টেলফিল্ডের উত্তরটি এরকম কিছুতে পরিবর্তিত হতে পারে:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

class Test(unittest.TestCase):
    @mock.patch('MyClass.last_transaction', new_callable=PropertyMock)
    def test(self, mock_last_transaction):
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()

6

আপনি pytestপাশাপাশি ব্যবহার করছেন এমন ক্ষেত্রে pytest-mock, আপনি আপনার কোডটি সহজ করতে পারেন এবং প্রসঙ্গের ব্যবস্থাটি ব্যবহার করা এড়াতে পারেন, অর্থাত্ withবিবৃতিটি নীচে:

def test_name(mocker): # mocker is a fixture included in pytest-mock
    mocked_property = mocker.patch(
        'MyClass.property_to_be_mocked',
        new_callable=mocker.PropertyMock,
        return_value='any desired value'
    )
    o = MyClass()

    print(o.property_to_be_mocked) # this will print: any desired value

    mocked_property.assert_called_once_with()

0

যদি আপনি পরীক্ষা করতে চান না যে উপহাসকৃত সম্পত্তি অ্যাক্সেস করা হয়েছে কিনা আপনি কেবল এটি প্রত্যাশার সাথে প্যাচ করতে পারেন return_value

with mock.patch(MyClass, 'last_transaction', Transaction()):
    ...

0

@propertyআসলটির উপর নির্ভর করার জন্য যদি আপনার উপহাসের প্রয়োজন হয় তবে __get__আপনি আপনার প্রথা তৈরি করতে পারেনMockProperty

class PropertyMock(mock.Mock):

    def __get__(self, obj, obj_type=None):
        return self(obj, obj_type)

ব্যবহার:

class A:

  @property
  def f(self):
    return 123


original_get = A.f.__get__

def new_get(self, obj_type=None):
  return f'mocked result: {original_get(self, obj_type)}'


with mock.patch('__main__.A.f', new_callable=PropertyMock) as mock_foo:
  mock_foo.side_effect = new_get
  print(A().f)  # mocked result: 123
  print(mock_foo.call_count)  # 1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.