From e81a9cbb17d33fff15381638e5040a8562a9bb2c Mon Sep 17 00:00:00 2001 From: Gerald Lonlas Date: Fri, 29 Dec 2017 23:12:52 -0800 Subject: [PATCH] Increase code coverage Change log: * Increase code coverage for test_exchange.py * Move Exchange Unit tests files tests/exchange/ * Move RPC Unit tests files tests/rpc/ --- freqtrade/tests/exchange/test_exchange.py | 188 ++++++++++++++++++ .../{ => exchange}/test_exchange_bittrex.py | 0 freqtrade/tests/{ => rpc}/test_rpc.py | 0 .../tests/{ => rpc}/test_rpc_telegram.py | 0 freqtrade/tests/test_exchange.py | 36 ---- 5 files changed, 188 insertions(+), 36 deletions(-) create mode 100644 freqtrade/tests/exchange/test_exchange.py rename freqtrade/tests/{ => exchange}/test_exchange_bittrex.py (100%) rename freqtrade/tests/{ => rpc}/test_rpc.py (100%) rename freqtrade/tests/{ => rpc}/test_rpc_telegram.py (100%) delete mode 100644 freqtrade/tests/test_exchange.py diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py new file mode 100644 index 000000000..2da657642 --- /dev/null +++ b/freqtrade/tests/exchange/test_exchange.py @@ -0,0 +1,188 @@ +# pragma pylint: disable=missing-docstring,C0103 +from unittest.mock import MagicMock +from requests.exceptions import RequestException +from random import randint +import logging +import pytest + +from freqtrade import OperationalException +from freqtrade.exchange import init, validate_pairs, buy, sell, get_balance, get_balances, \ + get_ticker, cancel_order, get_name, get_fee + + +def test_init(default_conf, mocker, caplog): + mocker.patch('freqtrade.exchange.validate_pairs', side_effect=lambda s: True) + init(config=default_conf) + assert ('freqtrade.exchange', + logging.INFO, + 'Instance is running with dry_run enabled' + ) in caplog.record_tuples + + +def test_init_exception(default_conf, mocker): + default_conf['exchange']['name'] = 'wrong_exchange_name' + + with pytest.raises( + OperationalException, + match='Exchange {} is not supported'.format(default_conf['exchange']['name'])): + init(config=default_conf) + + +def test_validate_pairs(default_conf, mocker): + api_mock = MagicMock() + api_mock.get_markets = MagicMock(return_value=[ + 'BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT', 'BTC_BCC', + ]) + mocker.patch('freqtrade.exchange._API', api_mock) + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + validate_pairs(default_conf['exchange']['pair_whitelist']) + + +def test_validate_pairs_not_available(default_conf, mocker): + api_mock = MagicMock() + api_mock.get_markets = MagicMock(return_value=[]) + mocker.patch('freqtrade.exchange._API', api_mock) + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + with pytest.raises(OperationalException, match=r'not available'): + validate_pairs(default_conf['exchange']['pair_whitelist']) + + +def test_validate_pairs_not_compatible(default_conf, mocker): + api_mock = MagicMock() + api_mock.get_markets = MagicMock(return_value=['BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT']) + default_conf['stake_currency'] = 'ETH' + mocker.patch('freqtrade.exchange._API', api_mock) + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + with pytest.raises(OperationalException, match=r'not compatible'): + validate_pairs(default_conf['exchange']['pair_whitelist']) + + +def test_validate_pairs_exception(default_conf, mocker, caplog): + api_mock = MagicMock() + api_mock.get_markets = MagicMock(side_effect=RequestException()) + mocker.patch('freqtrade.exchange._API', api_mock) + + # with pytest.raises(RequestException, match=r'Unable to validate pairs'): + validate_pairs(default_conf['exchange']['pair_whitelist']) + assert ('freqtrade.exchange', + logging.WARNING, + 'Unable to validate pairs (assuming they are correct). Reason: ' + ) in caplog.record_tuples + + +def test_buy_dry_run(default_conf, mocker): + default_conf['dry_run'] = True + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert 'dry_run_buy_' in buy(pair='BTC_ETH', rate=200, amount=1) + + +def test_buy_prod(default_conf, mocker): + api_mock = MagicMock() + api_mock.buy = MagicMock(return_value='dry_run_buy_{}'.format(randint(0, 10**6))) + mocker.patch('freqtrade.exchange._API', api_mock) + + default_conf['dry_run'] = False + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert 'dry_run_buy_' in buy(pair='BTC_ETH', rate=200, amount=1) + + +def test_sell_dry_run(default_conf, mocker): + default_conf['dry_run'] = True + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert 'dry_run_sell_' in sell(pair='BTC_ETH', rate=200, amount=1) + + +def test_sell_prod(default_conf, mocker): + api_mock = MagicMock() + api_mock.sell = MagicMock(return_value='dry_run_sell_{}'.format(randint(0, 10**6))) + mocker.patch('freqtrade.exchange._API', api_mock) + + default_conf['dry_run'] = False + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert 'dry_run_sell_' in sell(pair='BTC_ETH', rate=200, amount=1) + + +def test_get_balance_dry_run(default_conf, mocker): + default_conf['dry_run'] = True + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert get_balance(currency='BTC') == 999.9 + + +def test_get_balance_prod(default_conf, mocker): + api_mock = MagicMock() + api_mock.get_balance = MagicMock(return_value=123.4) + mocker.patch('freqtrade.exchange._API', api_mock) + + default_conf['dry_run'] = False + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert get_balance(currency='BTC') == 123.4 + + +def test_get_balances_dry_run(default_conf, mocker): + default_conf['dry_run'] = True + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert get_balances() == [] + + +def test_get_balances_prod(default_conf, mocker): + balance_item = { + 'Currency': '1ST', + 'Balance': 10.0, + 'Available': 10.0, + 'Pending': 0.0, + 'CryptoAddress': None + } + + api_mock = MagicMock() + api_mock.get_balances = MagicMock(return_value=[balance_item, balance_item, balance_item]) + mocker.patch('freqtrade.exchange._API', api_mock) + + default_conf['dry_run'] = False + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert len(get_balances()) == 3 + assert get_balances()[0]['Currency'] == '1ST' + assert get_balances()[0]['Balance'] == 10.0 + assert get_balances()[0]['Available'] == 10.0 + assert get_balances()[0]['Pending'] == 0.0 + + +def test_get_ticker(mocker, ticker): + + api_mock = MagicMock() + api_mock.get_ticker = MagicMock(return_value=ticker()) + mocker.patch('freqtrade.exchange._API', api_mock) + + ticker = get_ticker(pair='BTC_ETH') + assert ticker['bid'] == 0.00001098 + assert ticker['ask'] == 0.00001099 + assert ticker['bid'] == 0.00001098 + + +def test_cancel_order_dry_run(default_conf, mocker): + default_conf['dry_run'] = True + mocker.patch.dict('freqtrade.exchange._CONF', default_conf) + + assert cancel_order(order_id='123') is None + + +def test_get_name(default_conf, mocker): + mocker.patch('freqtrade.exchange.validate_pairs', side_effect=lambda s: True) + default_conf['exchange']['name'] = 'bittrex' + init(default_conf) + + assert get_name() == 'Bittrex' + + +def test_get_fee(default_conf, mocker): + mocker.patch('freqtrade.exchange.validate_pairs', side_effect=lambda s: True) + init(default_conf) + + assert get_fee() == 0.0025 diff --git a/freqtrade/tests/test_exchange_bittrex.py b/freqtrade/tests/exchange/test_exchange_bittrex.py similarity index 100% rename from freqtrade/tests/test_exchange_bittrex.py rename to freqtrade/tests/exchange/test_exchange_bittrex.py diff --git a/freqtrade/tests/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py similarity index 100% rename from freqtrade/tests/test_rpc.py rename to freqtrade/tests/rpc/test_rpc.py diff --git a/freqtrade/tests/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py similarity index 100% rename from freqtrade/tests/test_rpc_telegram.py rename to freqtrade/tests/rpc/test_rpc_telegram.py diff --git a/freqtrade/tests/test_exchange.py b/freqtrade/tests/test_exchange.py deleted file mode 100644 index 78bb89bfc..000000000 --- a/freqtrade/tests/test_exchange.py +++ /dev/null @@ -1,36 +0,0 @@ -# pragma pylint: disable=missing-docstring,C0103 -from unittest.mock import MagicMock - -import pytest - -from freqtrade import OperationalException -from freqtrade.exchange import validate_pairs - - -def test_validate_pairs(default_conf, mocker): - api_mock = MagicMock() - api_mock.get_markets = MagicMock(return_value=[ - 'BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT', 'BTC_BCC', - ]) - mocker.patch('freqtrade.exchange._API', api_mock) - mocker.patch.dict('freqtrade.exchange._CONF', default_conf) - validate_pairs(default_conf['exchange']['pair_whitelist']) - - -def test_validate_pairs_not_available(default_conf, mocker): - api_mock = MagicMock() - api_mock.get_markets = MagicMock(return_value=[]) - mocker.patch('freqtrade.exchange._API', api_mock) - mocker.patch.dict('freqtrade.exchange._CONF', default_conf) - with pytest.raises(OperationalException, match=r'not available'): - validate_pairs(default_conf['exchange']['pair_whitelist']) - - -def test_validate_pairs_not_compatible(default_conf, mocker): - api_mock = MagicMock() - api_mock.get_markets = MagicMock(return_value=['BTC_ETH', 'BTC_TKN', 'BTC_TRST', 'BTC_SWT']) - default_conf['stake_currency'] = 'ETH' - mocker.patch('freqtrade.exchange._API', api_mock) - mocker.patch.dict('freqtrade.exchange._CONF', default_conf) - with pytest.raises(OperationalException, match=r'not compatible'): - validate_pairs(default_conf['exchange']['pair_whitelist'])