Files
luoluo/tests/test_game_window.py

375 lines
14 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.
"""
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)