autool/win_start.py
2026-06-17 19:44:18 +08:00

203 lines
6.4 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.

#!/usr/bin/env python3
"""
Windows 平台自动化测试启动脚本
此脚本用于启动 Windows 桌面应用程序的自动化测试。
与 Android 版本不同Windows 版本不需要从 CSV 文件读取参数,
而是直接通过 Config 类配置或命令行参数指定目标窗口或可执行文件。
用法示例:
#修改 Config 类中的默认值后直接运行
python start_windows.py
"""
import argparse
import os
import subprocess
import sys
from pathlib import Path
from datetime import datetime
from dataclasses import dataclass
from typing import Optional
# 找到项目根目录
ROOT = Path(__file__).resolve().parent
# 确保根目录在Python路径中
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
@dataclass
class Config:
"""
Windows 平台测试配置
修改此类中的属性来设置默认值,然后直接运行 python start_windows.py 即可。
"""
# ===== Windows 必要参数 =====
# DAVE THE DIVER Counter-Strike 2
WINDOW_TITLE: str = "old - 记事本"
# 可执行文件路径(可选)。如果窗口未找到,将使用此路径启动应用
# 例如: "C:\\Windows\\System32\\notepad.exe"
EXE_PATH: Optional[str] = None
# Steam 游戏 ID可选。如果指定将使用 steam://rungameid/{ID} 启动游戏
# 例如: CS2 = 730, DAVE THE DIVER = 1868140
STEAM_GAME_ID: Optional[str] = None
# ===== 输出配置 =====
# 输出目录基础路径,实际目录会自动添加时间戳
OUTPUT_BASE_DIR: str = "./win_output"
# ===== 测试策略配置 =====
# 测试策略: "none", "memory_guided", "manual"
POLICY: str = "memory_guided"
# 测试超时时间(秒)
TIMEOUT: int = 3600
# 要生成的事件总数
EVENT_COUNT: int = 1000
# 每两个事件之间的间隔(秒)
EVENT_INTERVAL: int = 1
# ===== 功能开关 =====
# 是否启用 GuiAgent 进行智能UI交互
ENABLE_GUIAGENT: bool = False
# 是否以调试模式运行
DEBUG_MODE: bool = False
# 是否为输入事件添加随机性
RANDOM_INPUT: bool = False
def generate_output_dir(window_title: str, base_dir: str = "./output") -> str:
"""
生成带时间戳的输出目录
格式: ./output/WindowTitle_YYYYMMDD_HHMMSS
"""
# 清理窗口标题,移除特殊字符
sanitized_title = "".join(c if c.isalnum() or c in ('_', '-') else '_' for c in window_title)
sanitized_title = sanitized_title[:30] # 限制长度
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
folder_name = f"{sanitized_title}_{timestamp}"
return os.path.join(base_dir, folder_name)
def run_droidbot_direct(config: Config, output_dir: str) -> None:
"""
直接调用 DroidBot 进行测试(不通过子进程)
"""
from DroidBot.droidbot import DroidBot
print(f"{'='*60}")
print(f"[INFO] 启动 Windows 平台自动化测试")
print(f"[INFO] 目标窗口: {config.WINDOW_TITLE}")
if config.EXE_PATH:
print(f"[INFO] 可执行文件: {config.EXE_PATH}")
if config.STEAM_GAME_ID:
print(f"[INFO] Steam 游戏 ID: {config.STEAM_GAME_ID}")
print(f"[INFO] 输出目录: {output_dir}")
print(f"[INFO] 测试策略: {config.POLICY}")
print(f"[INFO] 超时时间: {config.TIMEOUT}")
print(f"{'='*60}\n")
# 创建 DroidBot 实例
droidbot = DroidBot(
package_name=config.STEAM_GAME_ID, # Windows 平台: package_name -> steam_game_id
app_name=config.WINDOW_TITLE, # Windows 平台: app_name -> window_title
device_serial=config.EXE_PATH, # Windows 平台: device_serial -> exe_path
is_emulator=False,
output_dir=output_dir,
policy_name=config.POLICY,
random_input=config.RANDOM_INPUT,
event_interval=config.EVENT_INTERVAL,
timeout=config.TIMEOUT,
event_count=config.EVENT_COUNT,
cv_mode=True, # Windows 平台默认使用 CV 模式
debug_mode=config.DEBUG_MODE,
keep_app=True, # Windows 应用通常不需要卸载
keep_env=True,
profiling_method=None,
grant_perm=False,
enable_accessibility_hard=False,
humanoid=None,
ignore_ad=False,
replay_output=None,
enable_guiagent=config.ENABLE_GUIAGENT,
platform="windows"
)
droidbot.start()
def main():
"""
主函数
"""
# 创建配置实例
config = Config()
# 验证参数
if not config.WINDOW_TITLE:
print("[ERROR] 必须在 Config 类中设置 WINDOW_TITLE")
sys.exit(1)
if config.EXE_PATH and not os.path.exists(config.EXE_PATH):
print(f"[WARN] 指定的可执行文件不存在: {config.EXE_PATH}")
print("[WARN] 将尝试直接通过窗口标题查找应用")
# 确定输出目录
output_dir = generate_output_dir(config.WINDOW_TITLE, config.OUTPUT_BASE_DIR)
# 规范化路径
output_dir = output_dir.replace('\\', '/')
# 创建输出目录
try:
os.makedirs(output_dir, exist_ok=True)
print(f"[INFO] 输出目录: {output_dir}")
except OSError as e:
print(f"[ERROR] 创建输出目录失败: {e}")
sys.exit(1)
# 保存命令日志
cmd_log_path = os.path.join(output_dir, "config_dump.txt")
with open(cmd_log_path, "w", encoding="utf-8") as f:
f.write(f"Window Title: {config.WINDOW_TITLE}\n")
f.write(f"Exe Path: {config.EXE_PATH or 'N/A'}\n")
f.write(f"Output Dir: {output_dir}\n")
f.write(f"Policy: {config.POLICY}\n")
f.write(f"Timeout: {config.TIMEOUT}\n")
f.write(f"Event Count: {config.EVENT_COUNT}\n")
f.write(f"Event Interval: {config.EVENT_INTERVAL}\n")
f.write(f"Enable GuiAgent: {config.ENABLE_GUIAGENT}\n")
f.write(f"Debug Mode: {config.DEBUG_MODE}\n")
f.write(f"Random Input: {config.RANDOM_INPUT}\n")
try:
# 直接调用 DroidBot
run_droidbot_direct(config, output_dir)
print(f"\n[SUCCESS] 测试任务完成")
except KeyboardInterrupt:
print(f"\n[WARN] 用户手动中断测试")
sys.exit(0)
except Exception as e:
print(f"\n[ERROR] 执行任务时发生异常: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()