optz
This commit is contained in:
@@ -3,7 +3,7 @@ import io
|
||||
import logging
|
||||
import unittest
|
||||
from concurrent.futures import Future
|
||||
from contextlib import ExitStack, redirect_stdout
|
||||
from contextlib import ExitStack, redirect_stderr, redirect_stdout
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
@@ -77,7 +77,7 @@ class TrendCollectorTests(unittest.TestCase):
|
||||
self.assertEqual(payload['deals'][0]['volume'], 100)
|
||||
|
||||
def test_main_registers_five_minute_collector_job(self):
|
||||
for strategy in ('trend', 'zt'):
|
||||
for strategy in ('trend', 'zt', 'etf'):
|
||||
with self.subTest(strategy=strategy), ExitStack() as stack:
|
||||
scheduler = Mock(running=True)
|
||||
stack.enter_context(patch.object(self.app, 'BackgroundScheduler', return_value=scheduler))
|
||||
@@ -101,6 +101,63 @@ class TrendCollectorTests(unittest.TestCase):
|
||||
scheduler.start.assert_called_once()
|
||||
scheduler.shutdown.assert_called_once_with(wait=True)
|
||||
|
||||
def test_main_rejects_unknown_strategy_before_starting_the_scheduler(self):
|
||||
scheduler = Mock(running=True)
|
||||
with patch.object(self.app, 'BackgroundScheduler', return_value=scheduler), \
|
||||
patch.object(self.app, 'require_windows', return_value=True), \
|
||||
patch.object(self.app, 'check_single_instance', return_value=True), \
|
||||
patch.object(self.app, 'wait_for_qmt_api') as wait_api, \
|
||||
patch.object(self.app.config, 'load'), \
|
||||
patch.object(self.app.config, 'global_config', SimpleNamespace(api_host='unused')), \
|
||||
patch.object(self.app.config, 'account_config', SimpleNamespace(strategy='bogus')), \
|
||||
patch.object(self.app, 'wait_for_any_key'), \
|
||||
patch('sys.stdin', io.StringIO('\n')), redirect_stderr(io.StringIO()) as err:
|
||||
self.assertEqual(self.app.main(), 1)
|
||||
self.assertIn('bogus', err.getvalue())
|
||||
scheduler.start.assert_not_called()
|
||||
wait_api.assert_not_called()
|
||||
|
||||
def test_main_reports_a_missing_global_config(self):
|
||||
scheduler = Mock(running=True)
|
||||
with patch.object(self.app, 'BackgroundScheduler', return_value=scheduler), \
|
||||
patch.object(self.app, 'require_windows', return_value=True), \
|
||||
patch.object(self.app, 'check_single_instance', return_value=True), \
|
||||
patch.object(self.app, 'wait_for_qmt_api') as wait_api, \
|
||||
patch.object(self.app.config, 'load'), \
|
||||
patch.object(self.app.config, 'global_config', None), \
|
||||
patch.object(self.app.config, 'account_config', None), \
|
||||
patch.object(self.app, 'wait_for_any_key'), \
|
||||
patch('sys.stdin', io.StringIO('\n')), redirect_stderr(io.StringIO()) as err:
|
||||
self.assertEqual(self.app.main(), 1)
|
||||
self.assertIn('config.load', err.getvalue())
|
||||
scheduler.add_job.assert_not_called()
|
||||
wait_api.assert_not_called()
|
||||
|
||||
|
||||
class ETFEtfConfigSummaryTests(unittest.TestCase):
|
||||
"""启动日志里的 ETF 配置概览:缺文件必须说清楚,且不抛异常。"""
|
||||
|
||||
def summary(self, etf_cfg):
|
||||
app = importlib.import_module('main')
|
||||
with patch.object(app.config, 'etf_config', etf_cfg, create=True):
|
||||
return app.describe_etf_config()
|
||||
|
||||
def test_missing_file_is_described_not_raised(self):
|
||||
self.assertIn('_etf.yaml', self.summary(None))
|
||||
|
||||
def test_symbols_and_codes_are_listed_in_config_order(self):
|
||||
from config import EtfConfig, EtfDefaults, EtfSymbolConfig
|
||||
cfg = EtfConfig(
|
||||
defaults=EtfDefaults(),
|
||||
symbols={
|
||||
'159915.SZ': EtfSymbolConfig(is_t0=True, buy_shares=1000, atr_multiplier=1.0, inner_step=0.7),
|
||||
'510300.SH': EtfSymbolConfig(is_t0=False, buy_shares=1000, atr_multiplier=1.0, inner_step=0.7),
|
||||
},
|
||||
)
|
||||
summary = self.summary(cfg)
|
||||
self.assertIn('2 只', summary)
|
||||
self.assertLess(summary.index('159915.SZ'), summary.index('510300.SH'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user