系列从 0 到 1 搭建桌面应用 UI 自动化测试框架上一篇第 1 篇先盘点约束再决定怎么做下一篇第 3 篇跑通业务主链路关键词UAC、UIPI、AppSession、窗口反查 PID、Tee本篇导读第一道真正的墙是权限第二道是进程。只要这两件事不稳后面所有用例都是沙上建塔。本篇讲清楚三件事为什么必须统一提权怎么做为什么 PID 不可信怎么用窗口反查 PID提权后日志为什么看不见怎么解决。一句话PID 不可信窗口才是事实多层 launcher UIPI 场景必须 EnumWindows 反查 承载校验。流程图一次入口执行的完整链路否是不通过通过否是python run.pyIsUserAnAdmin() 1?ShellExecute runas 重新拉起taskkill 清理残留 DesktopApp.exepytest tests/AppSession.start()Application.start()EnumWindows 枚举顶层窗口从窗口句柄反查候选 PID排除系统窗口 / Qt 辅助窗口 / 浏览器窗口connect(processpid)该 PID 承载桌面应用窗口返回可用 Application1. 统一提权原则提权代码只能有一份所有入口脚本都复用它。# utils/elevation.py 的调用方式fromutils.elevationimportelevate,is_adminifnotis_admin():returnelevate(sys.argv[1:])三个入口都遵循这个模式run.py主测试入口run_endurance.py稳定性测试入口tools/dump_controls.py控件探针。已经在管理员终端里时用-noelevate跳过重复提权。为什么必须提权DesktopApp.exe 自身以 runas 启动。Windows 的 UIPI用户界面特权隔离规定低权限进程不能访问高权限进程的窗口。真实表现ProcessNotFoundError枚举不到窗口connect 后 PID 瞬间消失descendants 访问报 AccessDenied。这不是“偶发问题”而是确定性行为。所以它必须成为入口的前置条件而不是用例里的兜底逻辑。2. 进程连接不能信 PID桌面应用的启动链条是普通进程 → runas 提权 spawn 中转进程 → 真正承载窗口的进程如果只用“最大 PID”或“第一个 DesktopApp.exe”去 connect很容易连到launcher 中转进程连上后没有窗口explorer.exe打开了应用安装目录窗口标题含应用名浏览器进程Allure 报告页面标题含应用名class 是Chrome_WidgetWin_1Qt 辅助窗口ToolSaveBits、Tooltip、MessageWnd。正确做法窗口反查 PID# 核心思路简化示意真实实现见 utils/app_session.pyApplication(backenduia).start(cmd_line...,work_dir...)# 候选 PID 不是从进程列表猜是从 EnumWindows 反查窗口句柄得到forpidincandidate_pids_from_enumwindows():try:appApplication(backenduia).connect(processpid)# _has_app_window校验该 PID 的窗口 class/title/auto_id 是否命中应用特征集if_has_app_window(app):returnappexceptRuntimeError:continue关键细节EnumWindows 反查 PID从窗口句柄反查进程而不是从进程列表猜窗口排除系统窗口CabinetWClass、Shell_TrayWnd、Progman、#32770等排除 Qt 辅助窗口ToolSaveBits、Tooltip、MessageWnd排除浏览器窗口Chrome_WidgetWin_1、Edge_WidgetWin_1connect 后立即校验如果该 PID 不承载桌面应用窗口抛错换下一个。这一步的验收标准不是“能连上”而是“打开资源管理器、打开浏览器、启动应用后仍然只连到正确进程”。3. 三种进程模式模式触发方式适用场景会话共享默认常规场景法整个会话只启动一次每用例重启RESTART_PER_TEST1需要强隔离的用例连接外部进程APP_PIDxxxx外部调试/注入场景close 不杀进程APP_PID模式有两个硬约束close()只断开引用不杀进程禁止restart()否则会杀掉用户手动启动的实例。这两个约束看起来很小但它们决定了一个调试工具能不能真正被使用。4. 提权后的日志可见性提权后run.py跑在独立控制台父进程IDE / Trae拿不到 stdout。解法是_Teeclass_Tee:同时写控制台和日志文件每次 write 立即 flush。def__init__(self,*streams):self.streamsstreamsdefwrite(self,text):forsinself.streams:s.write(text)s.flush()defflush(self):forsinself.streams:s.flush()效果外部可以轮询logs/YYYYMMDD/run_HHMMSS.log实时看进度。5. 关键文件职责文件提权utils/elevation.py应用生命周期utils/app_session.py主入口run.py稳定性入口run_endurance.py6. 本步的坑现象根因修正pytest 枚举不到窗口测试进程低权限入口统一提权connect 到 explorer / 浏览器 / launcher只按 PID 或标题猜进程窗口反查 PID 承载校验提权后看不到输出stdout 在独立控制台Tee 到日志文件外部实例被测试杀掉close()无条件杀进程APP_PID模式只断开不杀7. 验收清单python run.py能自动弹 UAC 并继续执行日志文件能看到每一步进度启动后能稳定找到承载窗口的 PID故意打开资源管理器/浏览器不会连错进程APP_PID模式下关闭测试不会杀掉外部实例。8. 可复用要点PID 不可信窗口才是事实多层 launcher / 提权启动的应用都适用。入口层只做入口的事提权、清理、跑 pytest、出报告不掺业务逻辑。提权会改变 I/O 边界所有依赖 stdout 的设计都要重新验证。关键代码示例示例 1统一提权入口真实utils/elevation.py节选12 行接入代码# run.py 的 3 行提权逻辑ifnotis_admin():# 把原始命令行参数透传给提权后的新进程sys.exit(elevate(sys.argv[1:]))# elevation.py 里的 elevate() 核心ShellExecuteW runasdefelevate(argsNone,window_state1):scriptPath(sys.argv[0]).resolve()cmdf{script}{subprocess.list2cmdline(args)}rcctypes.windll.shell32.ShellExecuteW(None,runas,sys.executable,cmd,str(script.parent),window_state,)return0ifrc32else1
企业数字化 ERP 产品动态
相关推荐
GPU 监控体系与性能分析——从 nvidia-smi 到 DCGM 一、为什么需要 GPU 监控?在前面的学习中,我们了解了 GPU 的三个核心性能指标:显存容量(Memory Capacity):决定模型和数据能否装入 GPU。显存带宽(Memory Bandwidth):决定… · 2026/11/5 6:53:32
TVM 的前世今生:从深度学习编译器到 AI 基础设施 1. 引言:为什么需要 TVM
2016 年前后,深度学习从学术圈走向工业界,TensorFlow、PyTorch、MXNet 等框架百花齐放。但一个尴尬的现实摆在所有工程师面前:模型训练在框架里很舒服,部署到真实硬件上却异常痛苦。
同一份模型… · 2026/11/5 6:52:32
Ontology 学习 二 参考:一文读懂 Ontology:连接数据、业务与 AI 的关键语义层
一文读懂 Ontology 背后的四大技术:RDF、OWL、SPARQL、SHACL
用 Ontology 为 AI 提供更准确、更统一的业务上下文。
大模型虽然能够理解自然语言,却未必真正理解企业… · 2026/11/5 6:52:32
ADS122U04与STM32F410RB工业温度采集方案:UART接口ADC实战详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
ADS122U04IPWR + PIC18F66K40:PT100/NTC高精度温度采集方案解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
Figma设计稿转LVGL嵌入式UI:自动化链路与工程实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
ADS122U04IPWR+PIC18F56K42实现0.1℃工业温度测量 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
工业温度测量信号链设计:ADS122U04与PIC18F57Q43实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 7:35:44
1km人口分布栅格数据处理:口径、裁剪与时间序列分析 去年帮一位做城市扩张研究的朋友处理人口栅格,他拿到一份 2000—2023 年的 1km 精度人口分布栅格数据,第一件事就是把研究区内的像元值全部加总,想直接得到总人口曲线。结果算出来的数比公开统计口径少了将近三成,他一度以为是数据… · 2026/11/5 7:34:44
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38