""" GameWindowManager 测试用例 测试环境要求: - Windows 操作系统 - Python 3.9+ - 安装依赖: pywin32, psutil 运行测试: python -m pytest tests/test_game_window.py -v python -m pytest tests/test_game_window.py::TestGameWindowManager::test_find_window_by_exe -v """ import unittest import time import sys from pathlib import Path from unittest.mock import Mock, patch, MagicMock import psutil # 添加项目根目录到路径 project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from src.core.game_window import GameWindowManager class TestGameWindowManager(unittest.TestCase): """GameWindowManager 测试类""" def setUp(self): """每个测试方法前执行""" self.manager = GameWindowManager() def tearDown(self): """每个测试方法后执行""" self.manager = None # ==================== 基础属性测试 ==================== def test_initial_state(self): """测试初始状态""" self.assertIsNone(self.manager.hwnd) self.assertIsNone(self.manager.process_id) self.assertFalse(self.manager.is_window_captured) self.assertEqual(self.manager.client_size, (0, 0)) self.assertEqual(self.manager.window_rect, (0, 0, 0, 0)) def test_game_constants(self): """测试游戏常量配置""" self.assertEqual(self.manager.GAME_EXE_NAME, "ycgame.exe") self.assertEqual(self.manager.GAME_WINDOW_TITLE, "桃源深处有人家") # ==================== 模拟窗口测试 ==================== @patch('src.core.game_window.win32gui') @patch('src.core.game_window.win32process') @patch('src.core.game_window.psutil') def test_find_window_by_exe_success(self, mock_psutil, mock_win32process, mock_win32gui): """测试通过exe名成功查找窗口""" # 模拟窗口句柄和进程ID mock_hwnd = 12345 mock_pid = 67890 # 设置模拟返回值 mock_win32gui.IsWindowVisible.return_value = True mock_win32gui.GetWindowText.return_value = "桃源深处有人家" mock_win32gui.GetWindowRect.return_value = (100, 100, 1100, 700) mock_win32process.GetWindowThreadProcessId.return_value = (None, mock_pid) # 模拟进程对象 mock_process = Mock() mock_process.exe.return_value = "C:\\Game\\ycgame.exe" mock_psutil.Process.return_value = mock_process # 模拟EnumWindows回调 def mock_enum_windows(callback, extra): callback(mock_hwnd, extra) return True mock_win32gui.EnumWindows = mock_enum_windows # 执行测试 result = self.manager.find_window_by_exe("ycgame.exe") # 验证结果 self.assertTrue(result) self.assertEqual(self.manager.hwnd, mock_hwnd) self.assertEqual(self.manager.process_id, mock_pid) self.assertTrue(self.manager.is_window_captured) self.assertEqual(self.manager.client_size, (1000, 600)) @patch('src.core.game_window.win32gui') @patch('src.core.game_window.win32process') @patch('src.core.game_window.psutil') def test_find_window_by_exe_not_found(self, mock_psutil, mock_win32process, mock_win32gui): """测试通过exe名未找到窗口""" # 模拟没有匹配的窗口 def mock_enum_windows(callback, extra): return True mock_win32gui.EnumWindows = mock_enum_windows result = self.manager.find_window_by_exe("nonexistent.exe") self.assertFalse(result) self.assertIsNone(self.manager.hwnd) @patch('src.core.game_window.win32gui') @patch('src.core.game_window.win32process') def test_find_window_by_title_success(self, mock_win32process, mock_win32gui): """测试通过标题成功查找窗口""" mock_hwnd = 12345 mock_pid = 67890 mock_win32gui.FindWindow.return_value = mock_hwnd mock_win32gui.GetWindowRect.return_value = (100, 100, 1100, 700) mock_win32process.GetWindowThreadProcessId.return_value = (None, mock_pid) result = self.manager.find_window_by_title("桃源深处有人家") self.assertTrue(result) self.assertEqual(self.manager.hwnd, mock_hwnd) self.assertEqual(self.manager.process_id, mock_pid) @patch('src.core.game_window.win32gui') def test_find_window_by_title_not_found(self, mock_win32gui): """测试通过标题未找到窗口""" mock_win32gui.FindWindow.return_value = 0 # 模拟EnumWindows也没有找到 def mock_enum_windows(callback, extra): return True mock_win32gui.EnumWindows = mock_enum_windows result = self.manager.find_window_by_title("不存在的窗口") self.assertFalse(result) self.assertIsNone(self.manager.hwnd) # ==================== 综合查找测试 ==================== @patch.object(GameWindowManager, 'find_window_by_exe') @patch.object(GameWindowManager, 'find_window_by_title') def test_find_window_use_exe_success(self, mock_find_by_title, mock_find_by_exe): """测试综合查找 - 通过exe成功""" mock_find_by_exe.return_value = True result = self.manager.find_window(use_exe=True) self.assertTrue(result) mock_find_by_exe.assert_called_once() mock_find_by_title.assert_not_called() @patch.object(GameWindowManager, 'find_window_by_exe') @patch.object(GameWindowManager, 'find_window_by_title') def test_find_window_use_exe_fail_then_title(self, mock_find_by_title, mock_find_by_exe): """测试综合查找 - exe失败后用标题""" mock_find_by_exe.return_value = False mock_find_by_title.return_value = True result = self.manager.find_window(use_exe=True) self.assertTrue(result) mock_find_by_exe.assert_called_once() mock_find_by_title.assert_called_once() @patch.object(GameWindowManager, 'find_window_by_title') def test_find_window_use_title_only(self, mock_find_by_title): """测试综合查找 - 只用标题""" mock_find_by_title.return_value = True result = self.manager.find_window(use_exe=False) self.assertTrue(result) mock_find_by_title.assert_called_once() # ==================== 窗口操作测试 ==================== @patch('src.core.game_window.win32gui') def test_bring_to_front(self, mock_win32gui): """测试窗口置前""" self.manager._hwnd = 12345 mock_win32gui.IsWindow.return_value = True self.manager.bring_to_front() mock_win32gui.SetForegroundWindow.assert_called_once_with(12345) @patch('src.core.game_window.win32gui') def test_bring_to_front_not_captured(self, mock_win32gui): """测试窗口未捕获时不执行置前""" mock_win32gui.IsWindow.return_value = False self.manager.bring_to_front() mock_win32gui.SetForegroundWindow.assert_not_called() @patch('src.core.game_window.win32gui') def test_click(self, mock_win32gui): """测试点击坐标转换""" self.manager._hwnd = 12345 mock_win32gui.IsWindow.return_value = True mock_win32gui.GetWindowRect.return_value = (100, 100, 1100, 700) # 执行点击 self.manager.click(500, 300) # 验证坐标转换 (窗口左上角100,100 + 相对坐标500,300 = 屏幕坐标600,400) # 注意:实际点击功能还未实现,这里只测试坐标转换逻辑 # ==================== 窗口信息测试 ==================== @patch('src.core.game_window.win32gui') @patch('src.core.game_window.psutil') def test_get_window_info_captured(self, mock_psutil, mock_win32gui): """测试获取窗口信息 - 已捕获""" mock_hwnd = 12345 mock_pid = 67890 self.manager._hwnd = mock_hwnd self.manager._process_id = mock_pid mock_win32gui.IsWindow.return_value = True mock_win32gui.GetWindowText.return_value = "桃源深处有人家" mock_win32gui.GetWindowRect.return_value = (100, 100, 1100, 700) mock_process = Mock() mock_process.exe.return_value = "C:\\Game\\ycgame.exe" mock_psutil.Process.return_value = mock_process info = self.manager.get_window_info() self.assertTrue(info["captured"]) self.assertEqual(info["hwnd"], mock_hwnd) self.assertEqual(info["title"], "桃源深处有人家") self.assertEqual(info["process_id"], mock_pid) self.assertEqual(info["exe_path"], "C:\\Game\\ycgame.exe") self.assertEqual(info["rect"], (100, 100, 1100, 700)) self.assertEqual(info["size"], (1000, 600)) def test_get_window_info_not_captured(self): """测试获取窗口信息 - 未捕获""" info = self.manager.get_window_info() self.assertFalse(info["captured"]) self.assertIsNone(info["hwnd"]) self.assertIsNone(info["title"]) self.assertIsNone(info["process_id"]) self.assertIsNone(info["exe_path"]) self.assertIsNone(info["rect"]) self.assertIsNone(info["size"]) # ==================== 错误处理测试 ==================== @patch('src.core.game_window.win32gui') @patch('src.core.game_window.win32process') @patch('src.core.game_window.psutil') def test_find_window_by_exe_access_denied(self, mock_psutil, mock_win32process, mock_win32gui): """测试访问被拒绝时的处理""" mock_win32gui.IsWindowVisible.return_value = True mock_win32process.GetWindowThreadProcessId.return_value = (None, 12345) mock_psutil.Process.side_effect = psutil.AccessDenied("Access denied") def mock_enum_windows(callback, extra): callback(12345, extra) return True mock_win32gui.EnumWindows = mock_enum_windows result = self.manager.find_window_by_exe("ycgame.exe") # 应该正常处理异常,返回False self.assertFalse(result) @patch('src.core.game_window.win32gui') def test_find_window_by_exe_exception(self, mock_win32gui): """测试异常情况处理""" mock_win32gui.EnumWindows.side_effect = Exception("Test exception") result = self.manager.find_window_by_exe("ycgame.exe") self.assertFalse(result) # ==================== 集成测试(需要实际游戏运行)==================== @unittest.skip("需要实际游戏运行") def test_integration_find_real_game_window_by_exe(self): """集成测试:查找真实游戏窗口(通过exe)""" result = self.manager.find_window_by_exe("ycgame.exe") if result: print(f"\n找到游戏窗口:") print(f" HWND: {self.manager.hwnd}") print(f" PID: {self.manager.process_id}") print(f" 大小: {self.manager.client_size}") info = self.manager.get_window_info() print(f" 标题: {info['title']}") print(f" 路径: {info['exe_path']}") else: print("\n未找到游戏窗口,请确保游戏已运行") # 不强制断言,因为游戏可能未运行 @unittest.skip("需要实际游戏运行") def test_integration_find_real_game_window_by_title(self): """集成测试:查找真实游戏窗口(通过标题)""" result = self.manager.find_window_by_title("桃源深处有人家") if result: print(f"\n找到游戏窗口:") print(f" HWND: {self.manager.hwnd}") print(f" 大小: {self.manager.client_size}") else: print("\n未找到游戏窗口,请确保游戏已运行") @unittest.skip("需要实际游戏运行") def test_integration_window_operations(self): """集成测试:窗口操作""" # 先捕获窗口 if not self.manager.capture_window(): self.skipTest("游戏未运行,跳过测试") # 测试获取信息 info = self.manager.get_window_info() self.assertTrue(info["captured"]) # 测试置前(不验证结果,只是确保不报错) try: self.manager.bring_to_front() except Exception as e: self.fail(f"bring_to_front 抛出异常: {e}") # 等待一下观察效果 time.sleep(1) class TestGameWindowManagerPerformance(unittest.TestCase): """性能测试""" @patch('src.core.game_window.win32gui') @patch('src.core.game_window.win32process') @patch('src.core.game_window.psutil') def test_find_window_performance(self, mock_psutil, mock_win32process, mock_win32gui): """测试查找窗口性能""" # 设置模拟数据 mock_win32gui.IsWindowVisible.return_value = True mock_win32gui.GetWindowText.return_value = "桃源深处有人家" mock_win32gui.GetWindowRect.return_value = (100, 100, 1100, 700) mock_win32process.GetWindowThreadProcessId.return_value = (None, 12345) mock_process = Mock() mock_process.exe.return_value = "C:\\Game\\ycgame.exe" mock_psutil.Process.return_value = mock_process def mock_enum_windows(callback, extra): for i in range(100): # 模拟100个窗口 callback(10000 + i, extra) return True mock_win32gui.EnumWindows = mock_enum_windows manager = GameWindowManager() # 测量查找时间 import time start = time.time() result = manager.find_window_by_exe("ycgame.exe") elapsed = time.time() - start self.assertTrue(result) self.assertLess(elapsed, 1.0, "查找窗口应该在一秒内完成") print(f"\n查找100个窗口耗时: {elapsed:.3f}秒") if __name__ == "__main__": # 运行测试 unittest.main(verbosity=2)