Python 3.x Python单元测试失败,因为来自模拟的StopIteration错误

Python 3.x Python单元测试失败,因为来自模拟的StopIteration错误,python-3.x,ccxt,Python 3.x,Ccxt,我正在使用mock测试一个类对象,它是ccxt.binance。这个模拟对象作为参数传递给我正在测试的函数。最初它是有效的,因为我能够在一定程度上进行测试。但是,当我更改所述对象的值时,函数不考虑该值,它返回StopIteration错误。我是不是错过了一些模拟设置?下面是代码的一个示例片段 下面是正在测试的代码 def-exchange\u-history\u加载(args、ccxt\u-exchange): #如果没有真正的fetchOHLCV或exchange没有特定于时间段的数据,则跳过

我正在使用mock测试一个类对象,它是ccxt.binance。这个模拟对象作为参数传递给我正在测试的函数。最初它是有效的,因为我能够在一定程度上进行测试。但是,当我更改所述对象的值时,函数不考虑该值,它返回StopIteration错误。我是不是错过了一些模拟设置?下面是代码的一个示例片段

下面是正在测试的代码

def-exchange\u-history\u加载(args、ccxt\u-exchange):
#如果没有真正的fetchOHLCV或exchange没有特定于时间段的数据,则跳过exchange
如果((不是ccxt_exchange.has['fetchOHLCV'])或(ccxt_exchange.has['fetchOHLCV']=='emulated')或
(不是ccxt_exchange.timeframes.get(args.timeframe)):
logging.warning(f'Skipping{ccxt_exchange.name}.)
返回
#检查数据库中是否有exchange。如果没有,则写入数据库。
exchange\u db\u data=get\u exchange(ccxt\u exchange.id)
如果不交换数据库数据:
在数据库中插入交换(ccxt\u exchange.id,ccxt\u exchange.name)
logging.info(f'Inserted{ccxt_exchange.name}到数据库.)
exchange\u db\u data=get\u exchange(ccxt\u exchange.id)
exchange\u db\u id=exchange\u db\u数据[0]
info(f'Fetched{ccxt_exchange.name}数据)
#负荷交换市场
市场=ccxt_交易所。加载_市场()
info(f'Loaded{ccxt_exchange.name}markets.)
返回交换数据库id,市场
下面是测试函数

@patch('src.cron.historical\u price.hp\u load\u data.insert\u exchange\u to\u db')
@补丁('src.cron.historical\u price.hp\u load\u data.get\u exchange')
@修补程序('ccxt.binance')
def测试交换历史加载(模拟二进制、模拟获取交换、模拟插入交换到数据库):
#为函数创建示例参数
args=argparse.Namespace(timeframe='1d')
#必要函数的模拟示例返回值
mock_get_exchange.side_effect=[无,(1,'二进制','二进制',(1,'二进制','二进制')]
mock_binance.return_value.has.return_value={'fetchOHLCV':True}
mock\u binance.return\u value.load\u markets.return\u value={
“BTC/USDT”:{
'id':'btcusdt',
“符号”:“BTC/USDT”,
“基本”:“BTC”,
‘报价’:‘USDT’,
“活动”:True
}
}
mock_binance.return_value.id.return_value='binance'
mock_binance.return_value.name.return_value='binance'
ccxt_exchange=ccxt.binance()
#案例1:exchange具有fetchOHLCV,timeframe,但不在数据库中
#使用案例1测试断言
交易所\数据库\ id,市场=交易所\历史\加载(args,ccxt\交易所)
断言类型(交换数据库id)==int
断言类型(市场)=dict
断言mock\u get\u exchange.call\u count==2
calls=[调用(mock\u binance.return\u value.id),调用(mock\u binance.return\u value.id)]
模拟\u获取\u交换。断言\u有\u调用(调用)
mock_insert_exchange_to_db.assert_调用_once()
mock_binance.return_value.load_markets.assert_called_once()
#案例2:exchange具有fetchOHLCV、时间表,并且在数据库中
#重置案例2的模拟调用
mock\u插入\u交换\u到\u db.reset\u mock()
mock\u get\u exchange.reset\u mock()
mock\u binance.return\u value.load\u markets.reset\u mock()
#使用案例2测试断言
交易所\数据库\ id,市场=交易所\历史\加载(args,ccxt\交易所)
断言类型(交换数据库id)==int
断言类型(市场)=dict
mock_get_exchange.assert_调用_once()
assert not mock_insert_exchange_to_db.called
mock_binance.return_value.load_markets.assert_called_once()
calls=[调用(mock\u binance.return\u value.id)]
模拟\u获取\u交换。断言\u有\u调用(调用)
#案例3:exchange没有真正的fetchOHLCV
#重置案例3的模拟调用
mock\u get\u exchange.reset\u mock()
mock\u插入\u交换\u到\u db.reset\u mock()
mock\u binance.reset\u mock()
mock_binance.return_value.has.return_value={'fetchOHLCV':True}
#mock\u binance.return\u value.load\u markets.reset\u mock()
#使用案例3测试断言
交易所\数据库\ id,市场=交易所\历史\加载(args,ccxt\交易所)
#断言不交换\u db\u id
#不要断言市场
assert not mock_get_exchange.called
assert not mock_insert_exchange_to_db.called
assert not mock\u binance.return\u value.load\u markets.called
案例1和案例2有效。但是对于案例3,会抛出一个错误

mock_binance = <MagicMock name='binance' id='140285596974272'>
mock_get_exchange = <MagicMock name='get_exchange' id='140285596584312'>
mock_insert_exchange_to_db = <MagicMock name='insert_exchange_to_db' id='140285596584480'>

    @patch('src.cron.historical_price.hp_load_data.insert_exchange_to_db')
    @patch('src.cron.historical_price.hp_load_data.get_exchange')
    @patch('ccxt.binance')
    def test_exchange_history_load(mock_binance, mock_get_exchange, mock_insert_exchange_to_db):
        # create sample arguments for function
        args = argparse.Namespace(timeframe='1d')

        # mock up sample return values for necessary functions
        mock_get_exchange.side_effect = [None, (1, 'binance', 'Binance'), (1, 'binance', 'Binance')]
        mock_binance.return_value.has.return_value = {'fetchOHLCV': True}
        mock_binance.return_value.load_markets.return_value = {
            'BTC/USDT': {
                'id': 'btcusdt',
                'symbol': 'BTC/USDT',
                'base': 'BTC',
                'quote': 'USDT',
                'active': True
            }
        }
        mock_binance.return_value.id.return_value = 'binance'
        mock_binance.return_value.name.return_value = 'Binance'

        ccxt_exchange = ccxt.binance()

        # case 1: exchange is not in database

        # test assertions with case 1
        exchange_db_id, markets = exchange_history_load(args, ccxt_exchange)
        assert type(exchange_db_id) == int
        assert type(markets) == dict
        assert mock_get_exchange.call_count == 2
        calls = [call(mock_binance.return_value.id), call(mock_binance.return_value.id)]
        mock_get_exchange.assert_has_calls(calls)
        mock_insert_exchange_to_db.assert_called_once()
        mock_binance.return_value.load_markets.assert_called_once()

        # case 2: exchange is in database

        # reset mock calls for case 2
        mock_insert_exchange_to_db.reset_mock()
        mock_get_exchange.reset_mock()
        mock_binance.return_value.load_markets.reset_mock()

        # test assertions with case 2
        exchange_db_id, markets = exchange_history_load(args, ccxt_exchange)
        assert type(exchange_db_id) == int
        assert type(markets) == dict
        mock_get_exchange.assert_called_once()
        assert not mock_insert_exchange_to_db.called
        mock_binance.return_value.load_markets.assert_called_once()
        calls = [call(mock_binance.return_value.id)]
        mock_get_exchange.assert_has_calls(calls)

        # case 3: exchange doesn't have true fetchOHLCV

        # reset_mock calls for case 3
        mock_get_exchange.reset_mock()
        mock_insert_exchange_to_db.reset_mock()
        mock_binance.reset_mock()
        mock_binance.return_value.has.return_value = {'fetchOHLCV': True}
        # mock_binance.return_value.load_markets.reset_mock()

        # test assertions with case 3
>       exchange_db_id, markets = exchange_history_load(args, ccxt_exchange)

test_cron/test_historical_price/test_hp_load_data.py:89: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../src/cron/historical_price/hp_load_data.py:75: in exchange_history_load
    exchange_db_data = get_exchange(ccxt_exchange.id)
/usr/lib/python3.6/unittest/mock.py:939: in __call__
    return _mock_self._mock_call(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

_mock_self = <MagicMock name='get_exchange' id='140285596584312'>
args = (<MagicMock name='binance().id' id='140285596659328'>,), kwargs = {}
self = <MagicMock name='get_exchange' id='140285596584312'>, _new_name = ''
_new_parent = None
_call = call(<MagicMock name='binance().id' id='140285596659328'>), seen = set()
skip_next_dot = False, do_method_calls = False, name = 'get_exchange'

    def _mock_call(_mock_self, *args, **kwargs):
        self = _mock_self
        self.called = True
        self.call_count += 1
        _new_name = self._mock_new_name
        _new_parent = self._mock_new_parent

        _call = _Call((args, kwargs), two=True)
        self.call_args = _call
        self.call_args_list.append(_call)
        self.mock_calls.append(_Call(('', args, kwargs)))

        seen = set()
        skip_next_dot = _new_name == '()'
        do_method_calls = self._mock_parent is not None
        name = self._mock_name
        while _new_parent is not None:
            this_mock_call = _Call((_new_name, args, kwargs))
            if _new_parent._mock_new_name:
                dot = '.'
                if skip_next_dot:
                    dot = ''

                skip_next_dot = False
                if _new_parent._mock_new_name == '()':
                    skip_next_dot = True

                _new_name = _new_parent._mock_new_name + dot + _new_name

            if do_method_calls:
                if _new_name == name:
                    this_method_call = this_mock_call
                else:
                    this_method_call = _Call((name, args, kwargs))
                _new_parent.method_calls.append(this_method_call)

                do_method_calls = _new_parent._mock_parent is not None
                if do_method_calls:
                    name = _new_parent._mock_name + '.' + name

            _new_parent.mock_calls.append(this_mock_call)
            _new_parent = _new_parent._mock_new_parent

            # use ids here so as not to call __hash__ on the mocks
            _new_parent_id = id(_new_parent)
            if _new_parent_id in seen:
                break
            seen.add(_new_parent_id)

        ret_val = DEFAULT
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
                raise effect

            if not _callable(effect):
>               result = next(effect)
E               StopIteration

/usr/lib/python3.6/unittest/mock.py:998: StopIteration
mock\u binance=
模拟获取交换=
模拟插入交换到数据库=
@修补程序('src.cron.historical\u price.hp\u load\u data.insert\u exchange\u to\u db')
@补丁('src.cron.historical\u price.hp\u load\u data.get\u exchange')
@修补程序('ccxt.binance')
def测试交换历史加载(模拟二进制、模拟获取交换、模拟插入交换到数据库):
#为函数创建示例参数
args=argparse.Namespace(timeframe='1d')
#必要函数的模拟示例返回值
mock_get_exchange.side_effect=[无,(1,'二进制','二进制',(1,'二进制','二进制')]
mock_binance.return_value.has.return_value={'fetchOHLCV':True}
mock\u binance.return\u value.load\u markets.return\u value={
“BTC/USDT”:{
'id':'btcusdt',
“符号”:“BTC/USDT”,
“基本”:“BTC”,
‘报价’:‘USDT’,
“活动”:True
}
}
mock_binance.return_value.id.return_value='binance'
mock_binance.return_value.name.return_value='binance'
ccxt_exchange=ccxt.binance()
#情况1:exchange不在数据库中
#使用案例1测试断言
交易所\数据库\ id,市场=交易所\历史\加载(args,ccxt\交易所)
断言类型(交换数据库id)==int
断言类型(市场)=dict
断言mock\u get\u exchange.call\u count==2
calls=[调用(mock\u binance.return\u value.id),调用(mock\u binance.return\u value.id)]
mock\u get\u exchange.assert\u has\u调用
In [1]: from fleeteng_fw_agent.hostinfo imfrom mock import MagicMock, 
PropertyMock, call, patch

In [2]: mock_get_exchange = MagicMock()

In [3]: mock_get_exchange.side_effect = [None, (1, 'binance', 'Binance'), (1, 
'binance', 'Binance')]

In [4]: mock_get_exchange
Out[4]: <MagicMock id='4310663120'>

In [5]: mock_get_exchange()

In [6]: mock_get_exchange()
Out[6]: (1, 'binance', 'Binance')

In [7]: mock_get_exchange()
Out[7]: (1, 'binance', 'Binance')

In [8]: mock_get_exchange()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-8-4d63b6292e10> in <module>()
----> 1 mock_get_exchange()

/Users/**/ in __call__(_mock_self, *args, **kwargs)
    954         # in the signature
    955         _mock_self._mock_check_sig(*args, **kwargs)
--> 956         return _mock_self._mock_call(*args, **kwargs)
    957 
    958 

/Users/**/ in _mock_call(_mock_self, *args, **kwargs)
   1012 
   1013             if not _callable(effect):
-> 1014                 result = next(effect)
   1015                 if _is_exception(result):
   1016                     raise result

StopIteration: