|
3 | 3 |
|
4 | 4 | 수동 잔고(토스 등)를 자동화 태스크에 통합하는 기능 테스트 |
5 | 5 | """ |
| 6 | +import json |
6 | 7 | import pytest |
7 | 8 | from decimal import Decimal |
8 | 9 | from unittest.mock import AsyncMock, MagicMock, patch |
@@ -726,6 +727,62 @@ async def get_latest_analysis_by_symbol(self, symbol): |
726 | 727 | assert notification_sent[0]["appropriate_buy_min"] == 23000.0 |
727 | 728 | assert notification_sent[0]["appropriate_sell_max"] == 28000.0 |
728 | 729 |
|
| 730 | + @pytest.mark.asyncio |
| 731 | + async def test_send_toss_price_recommendation_parses_json_reasons(self, monkeypatch): |
| 732 | + """DB에 JSON 문자열로 저장된 근거를 리스트로 파싱해 전달""" |
| 733 | + from app.tasks.kis import _send_toss_recommendation_async |
| 734 | + from app.models.analysis import StockAnalysisResult |
| 735 | + |
| 736 | + notification_sent = [] |
| 737 | + |
| 738 | + class MockNotifier: |
| 739 | + _enabled = True |
| 740 | + |
| 741 | + async def notify_toss_price_recommendation(self, **kwargs): |
| 742 | + notification_sent.append(kwargs) |
| 743 | + return True |
| 744 | + |
| 745 | + mock_analysis = MagicMock(spec=StockAnalysisResult) |
| 746 | + mock_analysis.decision = "buy" |
| 747 | + mock_analysis.confidence = 70 |
| 748 | + mock_analysis.reasons = json.dumps( |
| 749 | + ["첫째 근거", "둘째 근거", "셋째 근거"], ensure_ascii=False |
| 750 | + ) |
| 751 | + mock_analysis.appropriate_buy_min = 23000.0 |
| 752 | + mock_analysis.appropriate_buy_max = 24000.0 |
| 753 | + mock_analysis.appropriate_sell_min = 26000.0 |
| 754 | + mock_analysis.appropriate_sell_max = 28000.0 |
| 755 | + mock_analysis.buy_hope_min = 22000.0 |
| 756 | + mock_analysis.buy_hope_max = 23000.0 |
| 757 | + mock_analysis.sell_target_min = 28000.0 |
| 758 | + mock_analysis.sell_target_max = 30000.0 |
| 759 | + |
| 760 | + class MockAnalysisService: |
| 761 | + def __init__(self, db): |
| 762 | + pass |
| 763 | + |
| 764 | + async def get_latest_analysis_by_symbol(self, symbol): |
| 765 | + return mock_analysis |
| 766 | + |
| 767 | + mock_db_session = MagicMock() |
| 768 | + mock_db_session.__aenter__ = AsyncMock(return_value=MagicMock()) |
| 769 | + mock_db_session.__aexit__ = AsyncMock(return_value=None) |
| 770 | + |
| 771 | + with patch('app.tasks.kis.get_trade_notifier', return_value=MockNotifier()), \ |
| 772 | + patch('app.core.db.AsyncSessionLocal', return_value=mock_db_session), \ |
| 773 | + patch('app.services.stock_info_service.StockAnalysisService', MockAnalysisService): |
| 774 | + |
| 775 | + await _send_toss_recommendation_async( |
| 776 | + code="015760", |
| 777 | + name="한국전력", |
| 778 | + current_price=25000.0, |
| 779 | + toss_quantity=10, |
| 780 | + toss_avg_price=23000.0, |
| 781 | + ) |
| 782 | + |
| 783 | + assert len(notification_sent) == 1 |
| 784 | + assert notification_sent[0]["reasons"] == ["첫째 근거", "둘째 근거", "셋째 근거"] |
| 785 | + |
729 | 786 | def test_format_toss_price_recommendation_html_escapes_special_chars(self): |
730 | 787 | """HTML 포맷 메시지가 특수문자를 올바르게 이스케이프하는지 확인""" |
731 | 788 | from app.monitoring.trade_notifier import TradeNotifier |
|
0 commit comments