【问题标题】:Patching class instance attribute which is a property of another class修补类实例属性,该属性是另一个类的属性
【发布时间】:2020-09-01 02:02:28
【问题描述】:
#atomlib/atomtools.py

class AtomTools:
    def __init__(self):
        self.atomcachehelper = None

    @property
    def cache(self):
        if not self.atomcachehelper:
             from atomlib.AtomCacheHelper import AtomCacheHelper
             self.atomcachehelper = AtomCacheHelper()
        return self.atomcachehelper


# wdm_oms_failures_detector.py 

import pandas as pd
from atomlib.atomtools import atomtools as atom

class WdmNetworkFailureDetector(object):
    def __init__(self,):
        self._cache_helper = atom.cache

    def update_wdm_cache_data(self) -> pd.DataFrame:
        df_oms = self._cache_helper.query_to_df()
        return df_oms

# conftest.py

import pytest

@pytest.fixture(scope='module')
def df_oms():
    path = 'some_path.csv'
    df_oms = pd.read_csv(path)
    return df_oms


# test_wdm_oms_failures_detector.py

from unittest.mock import patch, PropertyMock, call
from wdm_oms_failures_detector WdmNetworkFailureDetector

wnfd = WdmNetworkFailureDetector()

class TestWdmNetworkFailureDetector(object):

    def test_get_mol_objects(self):
        pass

    @patch('wdm_oms_failures_detector.atom.cache')
    def test_update_wdm_cache_data(self, mocked_cache, df_oms):

        # Setup
        mocked_cache.return_value.query_to_df.return_value = df_oms
        # Exercise
        wnfd.update_wdm_cache_data()
        # Verify
        mocked_cache.return_value.query_to_df.assert_called_once()

我正在尝试修补 WdmNetworkFailureDetector 类的实例属性 atom.cache,它是 atomtools 的一个属性,它返回和 AtomCacheHelper 对象。然后我想模拟 AtomCacheHelper 的 query_to_df 方法并返回夹具。我不确定如何正确执行,我尝试了几种方法,其中大多数导致相同的 AttributeErrors:

....
     elif kwargs:
            # can't set keyword args when we aren't creating the mock
            # XXXX If new is a Mock we could call new.configure_mock(**kwargs)
            raise TypeError("Can't pass kwargs to a mock we aren't creating")

        new_attr = new

        self.temp_original = original
        self.is_local = local
>       setattr(self.target, self.attribute, new_attr)
E       AttributeError: can't set attribute

....
self = <unittest.mock._patch object at 0x000001E9B1618940>, exc_info = (<class 'AttributeError'>, AttributeError("can't set attribute",), <traceback object at 0x000001E9B17EEF48>)

    def __exit__(self, *exc_info):
        """Undo the patch."""
        if not _is_started(self):
            raise RuntimeError('stop called on unstarted patcher')

        if self.is_local and self.temp_original is not DEFAULT:
            setattr(self.target, self.attribute, self.temp_original)
        else:
>           delattr(self.target, self.attribute)
E           AttributeError: can't delete attribute

【问题讨论】:

    标签: python unit-testing mocking pytest


    【解决方案1】:

    问题是你在补丁之外实例化你的测试类,所以缓存助手是用真实对象初始化的,以后打补丁不会改变它,因为它已经分配给变量。您必须在修补期间进行实例化:

    test_wdm_oms_failures_detector.py

    from unittest.mock import patch
    
    from wdm_oms_failures_detector import WdmNetworkFailureDetector
    
    
    class TestWdmNetworkFailureDetector(object):
    
        @patch('wdm_oms_failures_detector.atom.cache')
        def test_update_wdm_cache_data(self, mocked_cache, df_oms):
            mocked_cache.return_value.query_to_df.return_value = df_oms
            wnfd = WdmNetworkFailureDetector()  # now the cache helper is set to the mock 
            wnfd.update_wdm_cache_data()
            mocked_cache.query_to_df.assert_called_once()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-16
      • 2011-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-05
      相关资源
      最近更新 更多