stock/tests/test_main.py

498 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
主程序模块单元测试
测试StockAnalysisSystem主类的功能
"""
import pytest
import asyncio
from unittest.mock import Mock, patch, AsyncMock
import sys
from io import StringIO
from src.main import StockAnalysisSystem
from src.utils.exceptions import StockSystemError
class TestStockAnalysisSystem:
"""股票分析系统测试类"""
@pytest.fixture
def stock_system(self):
"""股票分析系统实例"""
return StockAnalysisSystem()
def test_initialization(self, stock_system):
"""测试系统初始化"""
assert stock_system.data_manager is None
assert stock_system.data_processor is None
assert stock_system.stock_repo is None
assert stock_system.task_scheduler is None
assert stock_system.is_initialized is False
@pytest.mark.asyncio
async def test_initialize_success(self, stock_system):
"""测试系统初始化成功"""
with patch.object(stock_system, "_setup_database") as mock_setup_db:
with patch.object(stock_system, "_setup_components") as mock_setup_comp:
result = await stock_system.initialize()
assert result is True
assert stock_system.is_initialized is True
mock_setup_db.assert_called_once()
mock_setup_comp.assert_called_once()
@pytest.mark.asyncio
async def test_initialize_already_initialized(self, stock_system):
"""测试重复初始化"""
# 第一次初始化
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# 第二次初始化
result = await stock_system.initialize()
assert result is False # 应该返回False因为已经初始化过
@pytest.mark.asyncio
async def test_initialize_database_failure(self, stock_system):
"""测试数据库初始化失败"""
with patch.object(stock_system, "_setup_database", side_effect=Exception("数据库错误")):
with pytest.raises(StockSystemError):
await stock_system.initialize()
assert stock_system.is_initialized is False
@pytest.mark.asyncio
async def test_initialize_components_failure(self, stock_system):
"""测试组件初始化失败"""
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components", side_effect=Exception("组件错误")):
with pytest.raises(StockSystemError):
await stock_system.initialize()
assert stock_system.is_initialized is False
@pytest.mark.asyncio
async def test_start_scheduler_success(self, stock_system):
"""测试启动调度器成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock调度器启动
with patch.object(stock_system.task_scheduler, "start", return_value=True):
result = await stock_system.start_scheduler()
assert result is True
@pytest.mark.asyncio
async def test_start_scheduler_not_initialized(self, stock_system):
"""测试未初始化时启动调度器"""
result = await stock_system.start_scheduler()
assert result is False
@pytest.mark.asyncio
async def test_start_scheduler_failure(self, stock_system):
"""测试启动调度器失败"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock调度器启动失败
with patch.object(stock_system.task_scheduler, "start", return_value=False):
result = await stock_system.start_scheduler()
assert result is False
@pytest.mark.asyncio
async def test_stop_scheduler_success(self, stock_system):
"""测试停止调度器成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock调度器停止
with patch.object(stock_system.task_scheduler, "stop", return_value=True):
result = await stock_system.stop_scheduler()
assert result is True
@pytest.mark.asyncio
async def test_stop_scheduler_not_initialized(self, stock_system):
"""测试未初始化时停止调度器"""
result = await stock_system.stop_scheduler()
assert result is False
@pytest.mark.asyncio
async def test_get_system_status_success(self, stock_system):
"""测试获取系统状态成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock组件状态
with patch.object(stock_system.data_manager, "get_stock_basic_info", return_value=[{"code": "000001"}]):
with patch.object(stock_system.stock_repo, "get_stock_basic_info", return_value=[Mock()]):
with patch.object(stock_system.task_scheduler, "get_job_status", return_value={"test_job": {}}):
with patch.object(stock_system.task_scheduler, "is_running", True):
status = await stock_system.get_system_status()
assert "initialization" in status
assert "data_sources" in status
assert "database" in status
assert "scheduler" in status
assert "data_statistics" in status
assert status["initialization"]["status"] == "已初始化"
assert status["scheduler"]["status"] == "运行中"
@pytest.mark.asyncio
async def test_get_system_status_not_initialized(self, stock_system):
"""测试未初始化时获取系统状态"""
status = await stock_system.get_system_status()
assert "initialization" in status
assert status["initialization"]["status"] == "未初始化"
@pytest.mark.asyncio
async def test_initialize_all_data_success(self, stock_system):
"""测试初始化所有数据成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock数据初始化器
mock_initializer = Mock()
mock_initializer.initialize_all_data.return_value = {
"stock_basic": {"count": 1000, "status": "成功"},
"daily_kline": {"count": 50000, "status": "成功"},
"financial_report": {"count": 2000, "status": "成功"}
}
with patch("src.data.data_initializer.DataInitializer", return_value=mock_initializer):
result = await stock_system.initialize_all_data()
assert "stock_basic" in result
assert "daily_kline" in result
assert "financial_report" in result
assert result["stock_basic"]["count"] == 1000
assert result["daily_kline"]["count"] == 50000
assert result["financial_report"]["count"] == 2000
@pytest.mark.asyncio
async def test_initialize_all_data_not_initialized(self, stock_system):
"""测试未初始化时初始化数据"""
result = await stock_system.initialize_all_data()
assert result == {}
@pytest.mark.asyncio
async def test_update_daily_data_success(self, stock_system):
"""测试更新每日数据成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock数据更新
with patch.object(stock_system.task_scheduler, "_update_daily_kline_data", return_value=True):
result = await stock_system.update_daily_data()
assert result is True
@pytest.mark.asyncio
async def test_update_daily_data_not_initialized(self, stock_system):
"""测试未初始化时更新数据"""
result = await stock_system.update_daily_data()
assert result is False
@pytest.mark.asyncio
async def test_update_financial_data_success(self, stock_system):
"""测试更新财务数据成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock数据更新
with patch.object(stock_system.task_scheduler, "_update_financial_data", return_value=True):
result = await stock_system.update_financial_data()
assert result is True
@pytest.mark.asyncio
async def test_update_stock_basic_info_success(self, stock_system):
"""测试更新股票基础信息成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
# Mock数据更新
with patch.object(stock_system.task_scheduler, "_update_stock_basic_info", return_value=True):
result = await stock_system.update_stock_basic_info()
assert result is True
class TestCommandLineInterface:
"""命令行接口测试类"""
@pytest.fixture
def capture_output(self):
"""捕获标准输出"""
old_stdout = sys.stdout
sys.stdout = StringIO()
yield sys.stdout
sys.stdout = old_stdout
def test_parse_arguments_init(self):
"""测试解析init命令参数"""
test_args = ["main.py", "init"]
with patch("sys.argv", test_args):
args = StockAnalysisSystem.parse_arguments()
assert args.command == "init"
assert args.force is False
def test_parse_arguments_scheduler(self):
"""测试解析scheduler命令参数"""
test_args = ["main.py", "scheduler", "--start"]
with patch("sys.argv", test_args):
args = StockAnalysisSystem.parse_arguments()
assert args.command == "scheduler"
assert args.start is True
assert args.stop is False
def test_parse_arguments_status(self):
"""测试解析status命令参数"""
test_args = ["main.py", "status"]
with patch("sys.argv", test_args):
args = StockAnalysisSystem.parse_arguments()
assert args.command == "status"
def test_parse_arguments_update(self):
"""测试解析update命令参数"""
test_args = ["main.py", "update", "--daily"]
with patch("sys.argv", test_args):
args = StockAnalysisSystem.parse_arguments()
assert args.command == "update"
assert args.daily is True
assert args.financial is False
assert args.basic is False
@pytest.mark.asyncio
async def test_run_init_command_success(self, stock_system, capture_output):
"""测试运行init命令成功"""
with patch.object(stock_system, "initialize", return_value=True):
with patch.object(stock_system, "initialize_all_data", return_value={"stock_basic": {"count": 1000}}):
result = await stock_system.run_command("init")
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "系统初始化成功" in output
assert "数据初始化完成" in output
@pytest.mark.asyncio
async def test_run_init_command_failure(self, stock_system, capture_output):
"""测试运行init命令失败"""
with patch.object(stock_system, "initialize", side_effect=StockSystemError("初始化失败")):
result = await stock_system.run_command("init")
assert result is False
# 检查输出
output = capture_output.getvalue()
assert "系统初始化失败" in output
@pytest.mark.asyncio
async def test_run_scheduler_start_command_success(self, stock_system, capture_output):
"""测试运行scheduler start命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
with patch.object(stock_system, "start_scheduler", return_value=True):
result = await stock_system.run_command("scheduler", start=True)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "定时任务调度器启动成功" in output
@pytest.mark.asyncio
async def test_run_scheduler_stop_command_success(self, stock_system, capture_output):
"""测试运行scheduler stop命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
with patch.object(stock_system, "stop_scheduler", return_value=True):
result = await stock_system.run_command("scheduler", stop=True)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "定时任务调度器停止成功" in output
@pytest.mark.asyncio
async def test_run_status_command_success(self, stock_system, capture_output):
"""测试运行status命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
mock_status = {
"initialization": {"status": "已初始化"},
"data_sources": {"akshare": "正常"},
"database": {"status": "正常"},
"scheduler": {"status": "运行中"},
"data_statistics": {"stock_count": 1000}
}
with patch.object(stock_system, "get_system_status", return_value=mock_status):
result = await stock_system.run_command("status")
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "系统状态" in output
assert "已初始化" in output
assert "运行中" in output
@pytest.mark.asyncio
async def test_run_update_daily_command_success(self, stock_system, capture_output):
"""测试运行update daily命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
with patch.object(stock_system, "update_daily_data", return_value=True):
result = await stock_system.run_command("update", daily=True)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "每日数据更新完成" in output
@pytest.mark.asyncio
async def test_run_update_financial_command_success(self, stock_system, capture_output):
"""测试运行update financial命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
with patch.object(stock_system, "update_financial_data", return_value=True):
result = await stock_system.run_command("update", financial=True)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "财务数据更新完成" in output
@pytest.mark.asyncio
async def test_run_update_basic_command_success(self, stock_system, capture_output):
"""测试运行update basic命令成功"""
# 先初始化系统
with patch.object(stock_system, "_setup_database"):
with patch.object(stock_system, "_setup_components"):
await stock_system.initialize()
with patch.object(stock_system, "update_stock_basic_info", return_value=True):
result = await stock_system.run_command("update", basic=True)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "股票基础信息更新完成" in output
class TestErrorHandling:
"""错误处理测试类"""
@pytest.mark.asyncio
async def test_handle_exception(self, stock_system, capture_output):
"""测试异常处理"""
# 模拟异常
try:
raise StockSystemError("测试异常")
except Exception as e:
result = stock_system._handle_exception(e)
assert result is False
# 检查输出
output = capture_output.getvalue()
assert "测试异常" in output
@pytest.mark.asyncio
async def test_handle_keyboard_interrupt(self, stock_system, capture_output):
"""测试键盘中断处理"""
# 模拟键盘中断
try:
raise KeyboardInterrupt()
except Exception as e:
result = stock_system._handle_exception(e)
assert result is True
# 检查输出
output = capture_output.getvalue()
assert "程序被用户中断" in output
@pytest.mark.asyncio
async def test_main_function_success(self, capture_output):
"""测试主函数成功执行"""
# Mock命令行参数和系统运行
test_args = ["main.py", "status"]
with patch("sys.argv", test_args):
with patch("src.main.StockAnalysisSystem.run_command", return_value=True):
from src.main import main
result = await main()
assert result == 0
@pytest.mark.asyncio
async def test_main_function_failure(self, capture_output):
"""测试主函数执行失败"""
# Mock命令行参数和系统运行失败
test_args = ["main.py", "status"]
with patch("sys.argv", test_args):
with patch("src.main.StockAnalysisSystem.run_command", return_value=False):
from src.main import main
result = await main()
assert result == 1