add more tests

This commit is contained in:
gcarq 2017-11-09 20:02:41 +01:00
parent 567ed4ecda
commit 80592970e9
2 changed files with 281 additions and 5 deletions

View File

@ -0,0 +1,66 @@
# pragma pylint: disable=missing-docstring
import pytest
from freqtrade.exchange import Exchanges
from freqtrade.persistence import Trade
def test_update(limit_buy_order, limit_sell_order):
trade = Trade(
pair='BTC_ETH',
stake_amount=1.00,
fee=0.1,
exchange=Exchanges.BITTREX,
)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
trade.open_order_id = 'something'
trade.update(limit_buy_order)
assert trade.open_order_id is None
assert trade.open_rate == 0.07256061
assert trade.close_profit is None
assert trade.close_date is None
trade.open_order_id = 'something'
trade.update(limit_sell_order)
assert trade.open_order_id is None
assert trade.open_rate == 0.07256061
assert trade.close_profit == 0.00546755
assert trade.close_date is not None
def test_update_open_order(limit_buy_order):
trade = Trade(
pair='BTC_ETH',
stake_amount=1.00,
fee=0.1,
exchange=Exchanges.BITTREX,
)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
limit_buy_order['closed'] = False
trade.update(limit_buy_order)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
def test_update_invalid_order(limit_buy_order):
trade = Trade(
pair='BTC_ETH',
stake_amount=1.00,
fee=0.1,
exchange=Exchanges.BITTREX,
)
limit_buy_order['type'] = 'invalid'
with pytest.raises(ValueError, match=r'Unknown order type'):
trade.update(limit_buy_order)

View File

@ -4,20 +4,36 @@ from datetime import datetime
from random import randint from random import randint
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest
from telegram import Bot, Update, Message, Chat from telegram import Bot, Update, Message, Chat
from telegram.error import NetworkError
from freqtrade.main import init, create_trade from freqtrade.main import init, create_trade
from freqtrade.misc import update_state, State, get_state from freqtrade.misc import update_state, State, get_state
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import telegram
from freqtrade.rpc.telegram import ( from freqtrade.rpc.telegram import (
_status, _status_table, _profit, _forcesell, _performance, _count, _start, _stop, _balance, _status, _status_table, _profit, _forcesell, _performance, _count, _start, _stop, _balance,
authorized_only) authorized_only, _help, is_enabled, send_msg
)
class MagicBot(MagicMock, Bot): class MagicBot(MagicMock, Bot):
pass pass
def test_is_enabled(default_conf, mocker):
mocker.patch.dict('freqtrade.rpc.telegram._CONF', default_conf)
default_conf['telegram']['enabled'] = False
assert is_enabled() is False
def test_init_disabled(default_conf, mocker):
mocker.patch.dict('freqtrade.rpc.telegram._CONF', default_conf)
default_conf['telegram']['enabled'] = False
telegram.init(default_conf)
def test_authorized_only(default_conf, mocker): def test_authorized_only(default_conf, mocker):
mocker.patch.dict('freqtrade.rpc.telegram._CONF', default_conf) mocker.patch.dict('freqtrade.rpc.telegram._CONF', default_conf)
@ -50,6 +66,19 @@ def test_authorized_only_unauthorized(default_conf, mocker):
assert state['called'] is False assert state['called'] is False
def test_authorized_only_exception(default_conf, mocker):
mocker.patch.dict('freqtrade.rpc.telegram._CONF', default_conf)
update = Update(randint(1, 100))
update.message = Message(randint(1, 100), 0, datetime.utcnow(), Chat(0, 0))
@authorized_only
def dummy_handler(*args, **kwargs) -> None:
raise Exception('test')
dummy_handler(MagicMock(), update)
def test_status_handle(default_conf, update, ticker, mocker): def test_status_handle(default_conf, update, ticker, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
@ -63,6 +92,18 @@ def test_status_handle(default_conf, update, ticker, mocker):
get_ticker=ticker) get_ticker=ticker)
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
update_state(State.STOPPED)
_status(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'trader is not running' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
update_state(State.RUNNING)
_status(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'no active trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
# Create some test data # Create some test data
trade = create_trade(15.0) trade = create_trade(15.0)
assert trade assert trade
@ -90,6 +131,17 @@ def test_status_table_handle(default_conf, update, ticker, mocker):
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value='mocked_order_id')) buy=MagicMock(return_value='mocked_order_id'))
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
update_state(State.STOPPED)
_status_table(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'trader is not running' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
update_state(State.RUNNING)
_status_table(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'no active order' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
# Create some test data # Create some test data
trade = create_trade(15.0) trade = create_trade(15.0)
@ -121,12 +173,23 @@ def test_profit_handle(default_conf, update, ticker, limit_buy_order, limit_sell
get_ticker=ticker) get_ticker=ticker)
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
_profit(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'no closed trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
# Create some test data # Create some test data
trade = create_trade(15.0) trade = create_trade(15.0)
assert trade assert trade
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
trade.update(limit_buy_order) trade.update(limit_buy_order)
_profit(bot=MagicBot(), update=update)
assert msg_mock.call_count == 2
assert 'no closed trade' in msg_mock.call_args_list[-1][0][0]
msg_mock.reset_mock()
# Simulate fulfilled LIMIT_SELL order for trade # Simulate fulfilled LIMIT_SELL order for trade
trade.update(limit_sell_order) trade.update(limit_sell_order)
@ -136,7 +199,7 @@ def test_profit_handle(default_conf, update, ticker, limit_buy_order, limit_sell
Trade.session.flush() Trade.session.flush()
_profit(bot=MagicBot(), update=update) _profit(bot=MagicBot(), update=update)
assert msg_mock.call_count == 2 assert msg_mock.call_count == 1
assert '*ROI:* `1.50701325 (10.05%)`' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* `1.50701325 (10.05%)`' in msg_mock.call_args_list[-1][0][0]
assert 'Best Performing:* `BTC_ETH: 10.05%`' in msg_mock.call_args_list[-1][0][0] assert 'Best Performing:* `BTC_ETH: 10.05%`' in msg_mock.call_args_list[-1][0][0]
@ -169,6 +232,42 @@ def test_forcesell_handle(default_conf, update, ticker, mocker):
assert '0.07256061 (profit: ~-0.64%)' in msg_mock.call_args_list[-1][0][0] assert '0.07256061 (profit: ~-0.64%)' in msg_mock.call_args_list[-1][0][0]
def test_forcesell_handle_invalid(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock())
init(default_conf, 'sqlite://')
# Trader is not running
update_state(State.STOPPED)
update.message.text = '/forcesell 1'
_forcesell(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
# No argument
msg_mock.reset_mock()
update_state(State.RUNNING)
update.message.text = '/forcesell'
_forcesell(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'Invalid argument' in msg_mock.call_args_list[0][0][0]
# Invalid argument
msg_mock.reset_mock()
update_state(State.RUNNING)
update.message.text = '/forcesell 123456'
_forcesell(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'no open trade' in msg_mock.call_args_list[0][0][0]
def test_performance_handle(default_conf, update, ticker, limit_buy_order, limit_sell_order, mocker): def test_performance_handle(default_conf, update, ticker, limit_buy_order, limit_sell_order, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True) mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
@ -217,6 +316,12 @@ def test_count_handle(default_conf, update, ticker, mocker):
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value='mocked_order_id')) buy=MagicMock(return_value='mocked_order_id'))
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
update_state(State.STOPPED)
_count(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
update_state(State.RUNNING)
# Create some test data # Create some test data
trade = create_trade(15.0) trade = create_trade(15.0)
@ -232,6 +337,25 @@ def test_count_handle(default_conf, update, ticker, mocker):
assert line[2] == '{}/{}'.format(2, default_conf['max_open_trades']) assert line[2] == '{}/{}'.format(2, default_conf['max_open_trades'])
def test_performance_handle_invalid(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_buy_signal', side_effect=lambda _: True)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock())
init(default_conf, 'sqlite://')
# Trader is not running
update_state(State.STOPPED)
_performance(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
def test_start_handle(default_conf, update, mocker): def test_start_handle(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock() msg_mock = MagicMock()
@ -243,7 +367,6 @@ def test_start_handle(default_conf, update, mocker):
_CONF=default_conf, _CONF=default_conf,
init=MagicMock()) init=MagicMock())
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
update_state(State.STOPPED) update_state(State.STOPPED)
assert get_state() == State.STOPPED assert get_state() == State.STOPPED
_start(bot=MagicBot(), update=update) _start(bot=MagicBot(), update=update)
@ -251,6 +374,25 @@ def test_start_handle(default_conf, update, mocker):
assert msg_mock.call_count == 0 assert msg_mock.call_count == 0
def test_start_handle_already_running(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
_CONF=default_conf,
init=MagicMock())
init(default_conf, 'sqlite://')
update_state(State.RUNNING)
assert get_state() == State.RUNNING
_start(bot=MagicBot(), update=update)
assert get_state() == State.RUNNING
assert msg_mock.call_count == 1
assert 'already running' in msg_mock.call_args_list[0][0][0]
def test_stop_handle(default_conf, update, mocker): def test_stop_handle(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock() msg_mock = MagicMock()
@ -262,7 +404,6 @@ def test_stop_handle(default_conf, update, mocker):
_CONF=default_conf, _CONF=default_conf,
init=MagicMock()) init=MagicMock())
init(default_conf, 'sqlite://') init(default_conf, 'sqlite://')
update_state(State.RUNNING) update_state(State.RUNNING)
assert get_state() == State.RUNNING assert get_state() == State.RUNNING
_stop(bot=MagicBot(), update=update) _stop(bot=MagicBot(), update=update)
@ -271,13 +412,39 @@ def test_stop_handle(default_conf, update, mocker):
assert 'Stopping trader' in msg_mock.call_args_list[0][0][0] assert 'Stopping trader' in msg_mock.call_args_list[0][0][0]
def test_stop_handle_already_stopped(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock(),
send_msg=msg_mock)
mocker.patch.multiple('freqtrade.main.exchange',
_CONF=default_conf,
init=MagicMock())
init(default_conf, 'sqlite://')
update_state(State.STOPPED)
assert get_state() == State.STOPPED
_stop(bot=MagicBot(), update=update)
assert get_state() == State.STOPPED
assert msg_mock.call_count == 1
assert 'already stopped' in msg_mock.call_args_list[0][0][0]
def test_balance_handle(default_conf, update, mocker): def test_balance_handle(default_conf, update, mocker):
mock_balance = [{ mock_balance = [{
'Currency': 'BTC', 'Currency': 'BTC',
'Balance': 10.0, 'Balance': 10.0,
'Available': 12.0, 'Available': 12.0,
'Pending': 0.0, 'Pending': 0.0,
'CryptoAddress': 'XXXX'}] 'CryptoAddress': 'XXXX',
}, {
'Currency': 'ETH',
'Balance': 0.0,
'Available': 0.0,
'Pending': 0.0,
'CryptoAddress': 'XXXX',
}]
mocker.patch.dict('freqtrade.main._CONF', default_conf) mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram', mocker.patch.multiple('freqtrade.main.telegram',
@ -291,3 +458,46 @@ def test_balance_handle(default_conf, update, mocker):
assert msg_mock.call_count == 1 assert msg_mock.call_count == 1
assert '*Currency*: BTC' in msg_mock.call_args_list[0][0][0] assert '*Currency*: BTC' in msg_mock.call_args_list[0][0][0]
assert 'Balance' in msg_mock.call_args_list[0][0][0] assert 'Balance' in msg_mock.call_args_list[0][0][0]
def test_help_handle(default_conf, update, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
msg_mock = MagicMock()
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock(),
send_msg=msg_mock)
_help(bot=MagicBot(), update=update)
assert msg_mock.call_count == 1
assert '*/help:* `This help message`' in msg_mock.call_args_list[0][0][0]
def test_send_msg(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock())
bot = MagicMock()
send_msg('test', bot)
assert len(bot.method_calls) == 0
bot.reset_mock()
default_conf['telegram']['enabled'] = True
send_msg('test', bot)
assert len(bot.method_calls) == 1
def test_send_msg_network_error(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch.multiple('freqtrade.main.telegram',
_CONF=default_conf,
init=MagicMock())
default_conf['telegram']['enabled'] = True
bot = MagicMock()
bot.send_message = MagicMock(side_effect=NetworkError('Oh snap'))
with pytest.raises(NetworkError, match=r'Oh snap'):
send_msg('test', bot)
# Bot should've tried to send it twice
assert len(bot.method_calls) == 2