import os import sys import unittest from pathlib import Path from unittest.mock import MagicMock, patch _ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(_ROOT / "src")) class TestConfig(unittest.TestCase): def setUp(self): self._saved = dict(os.environ) def tearDown(self): os.environ.clear() os.environ.update(self._saved) @patch("config._load_dotenv_if_present") def test_load_config_defaults_game_count(self, _): os.environ["LOTTO_USERNAME"] = "u" os.environ["LOTTO_PASSWORD"] = "p" os.environ["TELEGRAM_BOT_TOKEN"] = "t" os.environ["TELEGRAM_CHAT_ID"] = "1" os.environ.pop("GAME_COUNT", None) from config import load_config c = load_config() self.assertEqual(c.GAME_COUNT, 5) @patch("config._load_dotenv_if_present") def test_load_config_game_count_invalid(self, _): os.environ["LOTTO_USERNAME"] = "u" os.environ["LOTTO_PASSWORD"] = "p" os.environ["TELEGRAM_BOT_TOKEN"] = "t" os.environ["TELEGRAM_CHAT_ID"] = "1" os.environ["GAME_COUNT"] = "6" from config import load_config with self.assertRaises(ValueError): load_config() @patch("config._load_dotenv_if_present") def test_load_config_missing_required(self, _): os.environ.pop("LOTTO_USERNAME", None) from config import load_config with self.assertRaises(OSError): load_config() class TestLottoBuyer(unittest.TestCase): @patch("lotto_buyer.requests.Session") def test_login_success(self, SessionCls): session = MagicMock() SessionCls.return_value = session session.cookies = {"JSESSIONID": "abc"} post_resp = MagicMock() post_resp.url = "https://dhlottery.co.kr/main.do" session.post.return_value = post_resp from lotto_buyer import LottoBuyer b = LottoBuyer("user", "pw") self.assertTrue(b.login()) session.get.assert_called_once() session.post.assert_called_once() @patch("lotto_buyer.requests.Session") def test_login_fails_no_cookie(self, SessionCls): session = MagicMock() SessionCls.return_value = session session.cookies = {} session.post.return_value = MagicMock(url="https://dhlottery.co.kr/") from lotto_buyer import LottoBuyer b = LottoBuyer("user", "pw") self.assertFalse(b.login()) @patch("lotto_buyer.requests.Session") def test_buy_success(self, SessionCls): session = MagicMock() SessionCls.return_value = session def get_side_effect(url, **kwargs): r = MagicMock() r.raise_for_status = MagicMock() if "getGameInfo" in url: r.json.return_value = {"curDrwNo": 1200} elif "myPage" in url: r.text = '보유금액9,000원' else: r.json.return_value = {} r.text = "" return r session.get.side_effect = get_side_effect def post_side_effect(url, data=None, **kwargs): r = MagicMock() r.raise_for_status = MagicMock() if "saveBuy" in url: r.json.return_value = { "result": { "resultMsg": "SUCCESS", "ary645Lotto": [ { "drwtNo1": 7, "drwtNo2": 14, "drwtNo3": 21, "drwtNo4": 28, "drwtNo5": 35, "drwtNo6": 42, } ], } } else: r.json.return_value = {} return r session.post.side_effect = post_side_effect from lotto_buyer import LottoBuyer b = LottoBuyer("u", "p") result = b.buy(game_count=1) self.assertTrue(result.success) self.assertEqual(result.round_number, 1200) self.assertEqual(result.total_price, 1000) self.assertEqual(result.games[0], [7, 14, 21, 28, 35, 42]) def test_parse_bought_numbers(self): from lotto_buyer import LottoBuyer b = LottoBuyer("u", "p") data = { "result": { "ary645Lotto": [ { "drwtNo1": 10, "drwtNo2": 9, "drwtNo3": 8, "drwtNo4": 7, "drwtNo5": 6, "drwtNo6": 5, } ] } } games = b._parse_bought_numbers(data) self.assertEqual(games, [[5, 6, 7, 8, 9, 10]]) class TestTelegramNotifier(unittest.TestCase): @patch("telegram_notifier.requests.post") def test_send_success_calls_api(self, post): post.return_value = MagicMock() post.return_value.raise_for_status = MagicMock() from telegram_notifier import TelegramNotifier n = TelegramNotifier("token", "123") n.send_success(100, [[1, 2, 3, 4, 5, 6]], 1000, 5000) post.assert_called_once() args, kwargs = post.call_args self.assertIn("api.telegram.org/bottoken/sendMessage", args[0]) self.assertEqual(kwargs["json"]["chat_id"], "123") self.assertIn("로또 구매 완료", kwargs["json"]["text"]) if __name__ == "__main__": unittest.main()