在注入类中模拟@property-依赖注入

时间:2019-06-11 01:05:22

标签: python unit-testing testing mocking python-unittest

在使用unitttest.mock和pytest将一个依赖类模拟到另一个依赖类时,我一直遇到一个问题。

我正在测试接收 GenericAPI 类的类 Card GenericAPI 类具有以下内容:

class GenericAPI(CardAPI):

    REQUEST = {
        'API': 'xxx',
        'CARDS_ENDPOINT': 'xxx',
        'DELAY': 0.1,
        'ENCODING': 'utf-8',
        'HEADER_AUTH': {'Authorization': 'Bearer cs{client_secret}'},
        'HEADER_CONTENT': {'Content-Type': 'application/json'},
    }

    def __init__(self, name):
        super().__init__(self)
        self.name = name
        self._value = None

    @classmethod
    def get_card(cls, name):

        try:
            response = requests.get(url=f'{cls.REQUEST["API"]}{cls.REQUEST["CARDS_ENDPOINT"]}?exact={name}')
            response.raise_for_status()
            return response.json()
        except requests.HTTPError as err:
            logger.debug(f'Card "{name}" not found. trying fuzzy match. Response: {err}')
            try:
                response = requests.get(url=f'{cls.REQUEST["API"]}{cls.REQUEST["CARDS_ENDPOINT"]}?fuzzy={name}')
                response.raise_for_status()
                return response.json()
            except requests.HTTPError as err:
                logger.debug(f'Card "{name}" not found. Response: {err}')
                raise ValueError

    @property
    def value(self):
        return self._value

    @value.getter
    def value(self):
        prices = self.get_card(name=self.name)['prices']
        self.value = dict({'foil': prices['usd_foil'], 'non-foil': prices['usd']})
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value

与之相关的 Card 类由

定义
class Card:

    def __new__(cls, *args, **kwargs):

        try:
            kwargs['external_api'].get_card(name=kwargs['name'])
            return super(Card, cls).__new__(cls)
        except ValueError:
            raise ValueError('Unable to instantiate Card with current value as it is not a valid card')

    def __init__(self, name, set_name=None, condition=None, foil=None, external_api=None):

        self.name = name
        self.set_name = set_name
        self.condition = condition
        self.foil = foil
        self._value = None
        self._external_api = external_api

    @property
    def value(self):
        return float(self.value)

    @value.getter
    def value(self):
        card = self._external_api(name=self.name)
        price = card.value

        if self.foil:
            self.value = price['foil']
            return self._value
        else:
            self.value = price['non-foil']
            return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value

测试定义如下:


GOOD_RESPONSE = {'object': 'card', 'id': '6b3a20ac-1860-4513-bb73-35d23b088b04', 'name': 'Mox Opal',
                 'oracle_id': 'de2440de-e948-4811-903c-0bbe376ff64d', 'multiverse_ids': [397719],
                 # lots more of info in json
                 'mtgo_id': 57258, 'prices': {'usd': '91.40', 'usd_foil': '111.66', 'eur': '69.87', 'tix': '30.29'}}

@pytest.fixture
def mock_external_api():
    m = MagicMock(spec=GenericAPI)
    m.get_card.return_value = GOOD_RESPONSE
    type(m).value = PropertyMock(return_value=GOOD_RESPONSE['prices'])
    print(m.value)
    return m

class TestCard:

    def test_card_price_is_float(self, mock_external_api):
        card = Card(name='mox opal', external_api=mock_external_api)
        assert isinstance(card.value, float)

错误如下:

=============================================================================================== FAILURES ================================================================================================
___________________________________________________________________________________ TestCard.test_card_price_is_float ____________________________________________________________________________________

self = <test_card.TestCard object at 0x7f3ffdbeffd0>, mock_external_api = <MagicMock spec='ScryfallAPI' id='139912816342632'>

    def test_card_price_is_float(self, mock_external_api):
        card = Card(name='mox opal', external_api=mock_external_api)
>       assert isinstance(card.value, float)
E       AssertionError: assert False
E        +  where False = isinstance(<MagicMock name='mock().value.__getitem__()' id='139912816374616'>, float)
E        +    where <MagicMock name='mock().value.__getitem__()' id='139912816374616'> = (<class 'collection_app.cards.Card'>, {'name': 'mox opal', 'set_name': None, 'condition': None, 'foil': None, '_value'...ck().value.__getitem__()' id='139912816374616'>, '_external_api': <MagicMock spec='GenericAPI' id='139912816342632'>}).value

collection_app/tests/unit/test_card.py:37: AssertionError
----------------------------------------------------------------------------------------- Captured stdout setup ------------------------------------------------------------------------------------------
{'usd': '91.40', 'usd_foil': '111.66', 'eur': '69.87', 'tix': '30.29'}
=================================================================================== 1 failed, 2 passed in 0.16 seconds ===================================================================================

这是什么错误? 我花了一些时间阅读unittest.mock文档,但我似乎不明白这里缺少什么。

0 个答案:

没有答案