簡體   English   中英

使用 unittest 模塊修補時,是否可以將 side_effect 分配給 python 中的類成員變量?

[英]Is it possible to assign a side_effect to a class member variable in python when patching using the unittest module?

是否可以修補類實例變量並強制它在每次引用時返回不同的值? 具體來說,我有興趣使用side_effect參數執行此操作

  • 我知道在修補方法時,可以將side_effect分配給模擬方法。 如果您將side_effect設置為一個列表,它將在每次調用時遍歷該列表並返回一個不同的值。
  • 我想對類實例變量做同樣的事情,但無法讓它工作,我看不到任何文檔來建議這是否可行

例子

from unittest.mock import patch

def run_test():
    myClass = MyClass()
    for i in range(2):
        print(myClass.member_variable)

class MyClass():
    def __init__(self):
        self.member_variable = None

@patch('test_me.MyClass.member_variable',side_effect=[1,2], create=True)
def test_stuff(my_mock):
    run_test()
    assert False

輸出

-------------- Captured stdout call ---------------------------------------------------------------------------------------------------------------------
None
None

期望輸出

-------------- Captured stdout call ---------------------------------------------------------------------------------------------------------------------
1
2
  • 要清楚 - 我知道我可以將member_variable包裝在get_member_variable method() 中 那不是我的問題。 我只想知道您是否可以使用 side_effect 修補成員變量。

side_effect可以是函數、可迭代對象或異常( https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect )。 我認為這就是它不起作用的原因。

另一種測試方法是:

>>> class Class:
...     member_variable = None
...
>>> with patch('__main__.Class') as MockClass:
...     instance = MockClass.return_value
...     instance.member_variable = 'foo'
...     assert Class() is instance
...     assert Class().member_variable == 'foo'
...

這是文檔: https : //docs.python.org/3/library/unittest.mock.html#unittest.mock.patch

在您設置的示例的情況下,我無法按照我的想法進行更改,您可能在本課程中有更多項目,並且這個想法可以幫助您。

不是對屬性產生副作用的最佳選擇,但它可以按我的需要工作。

PS:我最終將讓我回答您的問題的代碼作為示例。

例子:

# -*- coding: utf-8 -*-
# !/usr/bin/env python3

import requests

from src.metaclasses.singleton import Singleton
from src.services.logger import new_logger
from src.exceptions.too_many_retries import TooManyRetries
from src.exceptions.unavailable_url import UnavailableURL

LOG = new_logger(__name__)


class PostbackService(metaclass=Singleton):
    def __init__(self):
        self.session = requests.session()

    def make_request(self, method, url, headers, data=None, retry=0):
        r = self.session.request(method, url, data=data, headers=headers)

        if r.status_code != 200:
            if retry < 3:
                return self.make_request(method, url, headers, data, retry + 1)
            message = f"Error performing request for url: {url}"
            LOG.error(message)
            raise TooManyRetries(message)

        return r.json()

測試:

# -*- coding: utf-8 -*-
# !/usr/bin/env python3
from unittest import TestCase
from unittest.mock import patch, MagicMock

from src.services.postback import PostbackService
from src.exceptions.too_many_retries import TooManyRetries
from src.exceptions.unavailable_url import UnavailableURL


class TestPostbackService(TestCase):
    @patch("src.services.postback.requests")
    def setUp(self, mock_requests) -> None:
        mock_requests.return_value = MagicMock()
        self.pb = PostbackService()

    def test_make_request(self):
        self.pb.session.request.return_value = MagicMock()

        url = "http://mock.io"
        header = {"mock-header": "mock"}
        data = {"mock-data": "mock"}
        mock_json = {"mock-json": "mock"}

        def _def_mock(value):
            """
            Returns a MagicMock with the status code changed for each request, so you can test the retry behavior of the application.
            """
            mock = MagicMock()
            mock.status_code = value
            mock.json.return_value = mock_json
            return mock

        self.pb.session.request.side_effect = [
            _def_mock(403),
            _def_mock(404),
            _def_mock(200),
        ]
        self.assertEqual(self.pb.make_request("GET", url, header, data), mock_json)

        self.pb.session.request.side_effect = [
            _def_mock(403),
            _def_mock(404),
            _def_mock(404),
            _def_mock(404),
        ]
        with self.assertRaises(TooManyRetries):
            self.pb.make_request("GET", url, header, data)

如您所見,我通過將每個的副作用更改為我想要做的來重新創建 magicmock。 它不是漂亮的代碼和超級 pythonic,但它按預期工作。 我使用@rsarai 從unittest 文檔發送的鏈接作為創建這個magicmock 對象的基礎。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM