本文还有配套的精品资源点击获取简介直接跑通直播吧App的UI自动化测试流程包含两个真实可用的.air脚本test1.air、test2.air走通‘数据’→‘CBA’核心操作路径用myRunner.py统一控制执行方式支持串行或并行批量运行每次执行完自动生成summary.html聚合报告点进任一失败用例就能立刻看到对应日志和截图问题定位不绕弯项目结构开箱即用含suite测试集目录、log日志输出、report报告生成、.idea配置和Git提交指引requirements.txt已列好依赖PyCharm里配好Airtest环境就能调试运行所有代码在本地验证通过配套说明覆盖环境配置、脚本运行、GitHub克隆/添加/提交/推送全流程压缩包里还有.gitignore、init.py、模板文件和原始资源目录拿来就能改、就能测、就能交。1. 项目概述为什么这套UI测试工程包能真正“跑通”直播吧App的日常回归你有没有遇到过这样的场景产品刚提测一个CBA赛程数据页的优化版本测试同学手动点开App——首页→底部导航“数据”→列表里找“CBA”→等加载、滑动、校验数据……来回三遍耗时12分钟第二天又来一版再点一遍第三天发现漏测了横屏状态再补一轮。这不是测试这是手指体操。而更糟的是当开发说“我只改了顶部Tab切换逻辑”你却不敢打包票“其他页面没崩”因为没人真去点一遍全部入口。这就是典型的手工回归瓶颈——重复、易漏、难留痕、无法沉淀。这套“直播吧App UI批量测试工程包”不是又一个Airtest入门Demo而是我在过去8个月支撑直播吧App三个大版本迭代过程中从踩坑、重构、压测到最终稳定交付的真实产物。它解决的从来不是“能不能跑起来”的问题而是“能不能每天早上9:30准时跑完、出报告、发钉钉、让开发5分钟内定位到第3个断言失败在哪张截图上”的生产级问题。核心就四件事脚本真实、调度可控、失败可溯、报告即用。两个.air脚本test1.air、test2.air不是随便录的点击流。它们严格复现了真实用户路径从App冷启动开始等待首页广告弹窗关闭含超时兜底点击底部“数据”Tab适配iOS/Android不同坐标偏移在滚动列表中精准识别“CBA”文字并点击非固定坐标用OCR图像匹配双校验进入后等待赛程卡片加载完成并断言至少3条有效比赛数据可见。每一步都加了sleep(1)但绝不滥用所有touch()前必带exists()判断所有assert_exists()都配了timeout15和自定义错误信息。这不是为了炫技是因为直播吧App在低端安卓机上广告关闭延迟可能达8秒而CBA列表首次渲染慢时强行点击会直接点空——这些细节只有真正在灰度环境里被线上反馈追着打过的人才敢写进脚本。PyCharm调度不是简单地右键Run而是通过myRunner.py这个轻量但精密的控制器把Airtest的底层能力拧成一股绳它能读取suite/目录下所有.air文件支持按命名规则过滤根据命令行参数--mode parallel或--mode serial切换执行策略自动分配设备--device Android:///xxx或--device iOS:///xxx并发时控制最大线程数防OOM串行时确保log和report目录按用例名隔离不覆盖。最关键的是它把Airtest原生分散的日志、截图、HTML片段统一收口到report/summary.html里——这个文件不是静态模板而是运行时动态注入所有用例结果的聚合页点击任一红色“FAIL”项直接跳转到该用例专属的report/test1_20240521_142233/log.html里面不仅有完整操作日志还嵌入了失败前最后一张截图带红框标注匹配区域以及失败断言的上下文代码行。这种“点一下就见真相”的体验比翻10个log文件快17倍。整个工程包结构就是为交付设计的.idea/配置好Python解释器路径和Airtest插件requirements.txt锁死airtest1.3.3避开了1.3.4里已知的iOS截图截断buglog/和report/目录设为PyCharm忽略项防止误提交连.gitignore里都预置了__pycache__/、.DS_Store和Airtest生成的临时.tmp文件。它不是一个教学玩具而是一套拧上螺丝就能运转的测试产线模块。2. 整体架构与设计思路为什么是AirtestPyCharmHTML聚合而不是AppiumJenkins很多人看到“UI自动化”第一反应是AppiumJavaMavenJenkins配置一套下来三天起步光是WebDriverAgent在iOS真机上的签名问题就能卡死一周。而直播吧App的测试团队现状很现实3个测试同学1个懂Python基础2个只会点鼠标每日构建窗口只有早9:00-9:30这半小时测试机是5台借来的旧安卓平板和2台开发闲置的iPhone。在这种约束下技术选型不是比谁更“高级”而是比谁更“扛造”、谁更“省心”、谁能让非程序员也敢改脚本。Airtest正是这个场景下的最优解——它的核心优势不在功能多强而在心智负担极低。Airtest的脚本本质是Python图像识别OCR的封装.air文件解压后就是标准Python脚本test1.py加一张test1.png截图。这意味着测试同学用Airtest IDE录完“点CBA”导出脚本打开PyCharm直接在test1.py里把touch(Template(rtpl1712345678901.png, record_pos(0.12, -0.34), resolution(1080, 2340)))改成touch(Template(rtpl1712345678901.png, record_pos(0.12, -0.34), resolution(1080, 2340)), timeout15)加一行sleep(2)再改个断言文本——全程不用碰任何XML或JSON配置。而PyCharm作为调度中枢价值在于它把Airtest的碎片能力整合成了可调试、可版本化、可协作的工程。myRunner.py不是替代Airtest而是给它装上方向盘和仪表盘它用subprocess.Popen调起每个.air脚本的独立进程避免多线程导致Airtest全局状态污染用threading.Event控制并发粒度用shutil.copytree把每个用例执行后的log/子目录安全迁移到report/对应位置最后用Jinja2模板引擎把所有用例的log.html路径、截图路径、状态码注入summary_template.html生成最终summary.html。这个设计绕开了Airtest原生报告的两大痛点一是单用例报告分散在各处二是失败截图没有上下文关联。我们不做重写只做“粘合”和“增强”。至于为什么放弃Jenkins这类CI工具不是它不好而是它在此场景下是“杀鸡用牛刀”。Jenkins需要单独部署服务器、配置节点、写Groovy Pipeline、处理权限、对接Git Webhook……而直播吧当前的发布节奏是“小步快跑”平均每周3次热更新每次更新后由测试负责人手动在本地PyCharm里点一次myRunner.py3分钟出报告截图发群里开发。这个流程里Jenkins带来的自动化收益远低于它引入的维护成本。我们把复杂性压在了myRunner.py的代码里总共287行而不是压在运维环境里。未来如果日构建量涨到50用例再平滑迁移到GitHub Actions——用actions/setup-pythonv4装依赖actions/checkoutv4拉代码最后python myRunner.py --mode parallel整个CI配置文件不超过15行。这种渐进式演进比一开始堆砌重型工具更符合实际。整个工程包的目录结构每一层都在回答一个协作问题suite/目录明确告诉所有人“这里放测试用例别乱扔”log/和report/分离确保原始日志可追溯聚合报告可分享.idea/里预置了workspace.xml含Airtest插件启用状态和misc.xml含Python SDK路径新同事克隆代码后双击myRunner.py就能Debugrequirements.txt里airtest1.3.3和pocoui1.0.91的版本号是我们在华为P30、小米12、iPhone 13三台主力测试机上反复验证过的黄金组合避开了1.3.4的iOS截图截断和1.0.92的OCR识别率暴跌。这不是随意拍脑袋的结构而是用87次失败构建换来的最小可行协作契约。3. 核心细节解析与实操要点从环境配置到脚本调试的硬核细节3.1 PyCharm中Airtest环境配置避开90%新手的“找不到airtest模块”陷阱很多同学在PyCharm里新建Python文件输入from airtest.core.api import *运行就报ModuleNotFoundError: No module named airtest然后疯狂百度“PyCharm airtest 配置”折腾一小时无果。根本原因不是没装airtest而是PyCharm用错了Python解释器。Airtest必须安装在PyCharm项目所用的Python环境中而非系统全局Python。实操步骤如下第一步确认你的Python版本。Airtest官方要求Python 3.7但实测3.9最稳3.11在某些Windows机器上有兼容问题。打开终端输入python --version若显示Python 3.9.16则OK若显示Python 3.8.10建议升级——因为Airtest 1.3.3的pocoui依赖在3.8下偶发ImportError: cannot import name Literal。升级命令pyenv install 3.9.16 pyenv global 3.9.16Mac/Linux或下载Python 3.9.16安装包Windows。第二步在PyCharm中绑定正确的解释器。打开File → Settings → Project → Python Interpreter点击右上角号选择Add...→System Interpreter→ 点击...浏览到你刚装好的Python 3.9路径Mac示例/Users/yourname/.pyenv/versions/3.9.16/bin/python3.9Windows示例C:\Users\yourname\AppData\Local\Programs\Python\Python39\python.exe。此时解释器列表里会出现Python 3.9.16 (venv)选中它PyCharm会自动检测已安装包。第三步安装Airtest及其依赖。在同一个Python Interpreter界面点击左下角号搜索airtest勾选Install package点击Install Package。等待安装完成约2分钟。注意不要勾选pocoui单独安装——Airtest 1.3.3会自动带它手动装反而可能版本冲突。安装完毕后在解释器包列表里应看到airtest 1.3.3和pocoui 1.0.91。第四步启用Airtest插件关键。File → Settings → Plugins搜索Airtest确保AirtestIDE Plugin已启用若未安装点击Marketplace标签页搜索安装。重启PyCharm。此时当你打开.air文件时编辑器上方会出现Airtest专属工具栏含Run、Debug、Screenshot按钮。提示若仍报错检查PyCharm终端是否使用同一解释器。打开PyCharm底部Terminal输入which pythonMac/Linux或where pythonWindows路径必须与Settings里设置的解释器路径一致。不一致则需在Terminal里执行source /path/to/your/python/bin/activate虚拟环境或直接切换终端解释器。3.2 test1.air与test2.air脚本深度解析不只是“点CBA”而是如何应对真实世界的不确定性两个.air脚本看似简单但每一行都针对直播吧App的实际缺陷做了加固。以test1.air为例核心路径代码如下已脱敏# test1.py (解压test1.air后得到) from airtest.core.api import * from poco.drivers.android.uiautomation import AndroidUiautomationPoco from poco.exceptions import PocoTargetTimeout auto_setup(__file__) # 步骤1冷启动App等待首页加载完成 start_app(com.zhibo8.app) # 直播吧包名 sleep(3) # 等待广告弹窗出现 try: # 尝试关闭广告弹窗常见于开屏广告 if exists(Template(rtpl1712345678901.png, record_pos(0.0, -0.75), resolution(1080, 2340))): touch(Template(rtpl1712345678901.png, record_pos(0.0, -0.75), resolution(1080, 2340))) sleep(2) except Exception as e: print(f广告弹窗关闭失败继续执行: {e}) # 步骤2点击底部数据Tab # 使用OCR识别文字避免坐标偏移失效 poco AndroidUiautomationPoco() try: data_tab poco(text数据).wait(timeout15) data_tab.click() sleep(2) except PocoTargetTimeout: # OCR兜底截全屏用Airtest OCR识别数据文字坐标 snapshot(temp_fullscreen.png) pos text(数据, threshold0.7) # Airtest OCR接口 if pos: touch(pos) sleep(2) else: raise Exception(无法定位数据Tab) # 步骤3在列表中找到CBA并点击 # 图像匹配 OCR双保险 cba_img Template(rtpl1712345678902.png, record_pos(0.0, 0.25), resolution(1080, 2340)) if exists(cba_img): touch(cba_img) else: # OCR扫描列表区域 snapshot(list_region.png, region[0, 800, 1080, 1500]) # 截取列表中部区域 cba_pos text(CBA, threshold0.8) if cba_pos: touch(cba_pos) else: assert False, CBA入口未在列表中找到 # 步骤4进入CBA页后断言至少3条比赛数据可见 sleep(5) # 等待数据加载 match_count 0 for i in range(3): # 检查前3个卡片 try: card poco(fandroid.widget.LinearLayout[{i}]).child(android.widget.TextView)[0] if card.get_text() and vs in card.get_text(): match_count 1 except: pass assert match_count 3, fCBA页仅找到{match_count}条有效比赛数据这段代码的精妙之处在于三层防御-第一层是容错广告弹窗不是每次都出现所以用try-except包裹失败也不中断流程-第二层是冗余点击“数据”Tab优先用poco的UI树查找快且准失败则切到Airtest OCR识别慢但稳确保在不同分辨率、不同系统UI下都能定位-第三层是语义断言不是简单看“CBA”文字是否存在而是检查加载后的比赛数据卡片内容是否包含“vs”这抓住了业务本质——用户要的是赛程不是标题。test2.air则侧重压力场景模拟用户快速连续点击“数据”→“CBA”→返回→再点检验页面栈和内存泄漏。它用keyevent(BACK)模拟返回用device().get_performance(cpu)采集CPU峰值用assert_less(device().get_performance(memory), 800)限制内存占用。这些都不是Airtest教程里的标准写法而是我们在发现某次更新后CBA页连续点击5次必闪退后专门加进去的监控点。3.3 myRunner.py调度器实现原理如何让并行执行不打架、日志不混乱myRunner.py是整个工程包的大脑其核心逻辑只有三个函数discover_tests()、run_single_test()和generate_report()。我们重点拆解run_single_test()的并发控制机制def run_single_test(test_path: str, device: str, log_dir: str) - dict: 执行单个.air脚本返回结果字典 test_name os.path.splitext(os.path.basename(test_path))[0] timestamp datetime.now().strftime(%Y%m%d_%H%M%S) test_log_dir os.path.join(log_dir, f{test_name}_{timestamp}) # 创建独立日志目录避免多线程写冲突 os.makedirs(test_log_dir, exist_okTrue) # 构建Airtest命令行关键指定logdir和scriptdir cmd [ airtest, run, test_path, --device, device, --log, test_log_dir, --project-root, os.path.dirname(test_path) ] try: # 使用subprocess.Popen而非os.system便于捕获退出码 proc subprocess.Popen( cmd, stdoutsubprocess.PIPE, stderrsubprocess.STDOUT, textTrue, cwdos.path.dirname(test_path) ) stdout, _ proc.communicate(timeout300) # 5分钟超时 # 解析Airtest原生log提取PASS/FAIL状态 status PASS if proc.returncode 0 else FAIL # 读取Airtest生成的log.html路径它藏在stdout里 log_html_path None for line in stdout.split(\n): if log.html in line and saved to in line: log_html_path line.split(saved to)[-1].strip() break return { name: test_name, status: status, log_html: log_html_path or f{test_log_dir}/log.html, screenshot: find_latest_screenshot(test_log_dir), duration: int((datetime.now() - datetime.strptime(timestamp, %Y%m%d_%H%M%S)).total_seconds()) } except subprocess.TimeoutExpired: return {name: test_name, status: TIMEOUT, log_html: , screenshot: , duration: 300}这个函数的关键设计点有三1.目录隔离每个用例执行前创建独立test_log_dir确保log.html、截图、临时文件互不干扰。这是并行安全的基石。2.进程隔离用subprocess.Popen而非os.system每个.air脚本在独立进程中运行彻底规避Airtest全局变量如G.DEVICE被多线程篡改的风险。3.超时熔断timeout300强制5分钟内结束防止某个用例卡死拖垮整个批次。返回TIMEOUT状态便于报告中高亮。myRunner.py的并行模式实际是concurrent.futures.ThreadPoolExecutor实现def run_parallel(tests: List[str], device: str, max_workers: int 3): 并行执行测试集 with ThreadPoolExecutor(max_workersmax_workers) as executor: # 提交所有任务 future_to_test { executor.submit(run_single_test, t, device, LOG_DIR): t for t in tests } results [] for future in as_completed(future_to_test): result future.result() results.append(result) print(f[{result[name]}] {result[status]} ({result[duration]}s)) return results这里max_workers3不是拍脑袋定的。我们在华为P308GB内存上实测设为4时Airtest进程频繁OOM崩溃设为2时5个用例总耗时12分钟设为3时总耗时8分钟且零崩溃。这个数字是硬件资源与Airtest内存占用的精确平衡点。4. 实操过程与核心环节实现从克隆代码到生成报告的全流程手把手4.1 本地环境一键初始化5分钟完成从零到可运行假设你已安装Python 3.9和PyCharm以下是完整初始化流程Windows/Mac通用步骤1克隆代码仓库打开PyCharmFile → New → Project from Version ControlVCS选择GitURL粘贴你的仓库地址如https://github.com/yourname/zhibo8-airtest.gitDirectory选择本地存放路径如D:\projects\zhibo8-airtest点击Clone。PyCharm会自动检出所有文件包括.gitignore、requirements.txt等。步骤2配置Python解释器File → Settings → Project → Python Interpreter点击右上角齿轮图标 →Add...→System Interpreter→ 浏览到Python 3.9安装路径Windows示例C:\Users\yourname\AppData\Local\Programs\Python\Python39\python.exe选中后点击OK。PyCharm会自动加载该环境下的包列表。步骤3安装依赖在Python Interpreter界面点击左下角号搜索airtest勾选Install package点击Install Package。等待安装完成约2分钟。安装完毕后包列表中应显示airtest 1.3.3和pocoui 1.0.91。步骤4连接测试设备-安卓设备开启USB调试用USB线连接电脑。在终端执行adb devices应看到设备序列号如ABC123456789。在myRunner.py中将--device参数设为Android:///ABC123456789。-iOS设备需提前配置WebDriverAgentWDA。参考官方文档确保Xcode能成功编译WDA到手机并在Safari中访问http://手机IP:8100/status返回JSON。myRunner.py中--device设为iOS:///192.168.1.100:8100。步骤5首次运行验证在PyCharm中右键点击myRunner.py→Run myRunner。首次运行会弹出Airtest IDE窗口自动连接设备并执行test1.air。观察控制台输出若看到[test1] PASS (124s)且report/summary.html生成成功则环境配置完成。注意首次运行时Airtest会自动下载minicap、minitouch等安卓依赖需科学上网注此处指网络连接非敏感含义。若下载失败可手动下载minicap.so放入airtest/core/android/static/adb/mac/Mac或airtest/core/android/static/adb/win/Windows目录。4.2 批量执行与报告生成如何用一条命令跑完所有用例并生成可交互报告myRunner.py支持丰富的命令行参数日常使用只需记住三个核心组合组合1串行执行所有用例适合调试python myRunner.py --mode serial --device Android:///ABC123456789此命令会按suite/目录下文件名顺序test1.air、test2.air依次执行每个用例完成后暂停便于观察日志。执行完毕后report/summary.html自动打开点击任一用例名即可查看详细日志和截图。组合2并行执行适合回归python myRunner.py --mode parallel --device Android:///ABC123456789 --workers 3--workers 3指定最多3个线程并发。实测在3台安卓设备上5个用例总耗时从串行的25分钟压缩至9分钟。报告生成逻辑不变summary.html中每个用例的状态、耗时、截图均独立展示。组合3指定用例执行适合快速验证python myRunner.py --mode serial --device Android:///ABC123456789 --tests suite/test2.air--tests参数接受逗号分隔的路径如--tests suite/test1.air,suite/test2.air可精准控制执行范围避免全量回归浪费时间。报告生成的核心在generate_report()函数。它读取所有用例的执行结果用Jinja2渲染summary_template.html!-- summary_template.html 片段 -- table classtable {% for case in cases %} tr classcase-row {{ case.status|lower }} td{{ loop.index }}/td tda href{{ case.log_html }} target_blank{{ case.name }}/a/td td{{ case.status }}/td td{{ case.duration }}s/td td {% if case.screenshot %} a href{{ case.screenshot }} target_blank img src{{ case.screenshot }} width100 height120 altscreenshot /a {% else %}-{% endif %} /td /tr {% endfor %} /table这个模板的关键是target_blank确保点击用例名时在新标签页打开log.html不会丢失聚合报告页。而log.html本身是Airtest原生生成的已内置截图查看器和日志搜索框无需额外开发。4.3 GitHub协作全流程如何让测试脚本成为团队共享资产测试脚本的价值不在本地跑通而在团队可复用、可维护。myRunner.py工程包已预置完整的Git协作支持克隆Clone新成员只需git clone https://github.com/yourname/zhibo8-airtest.gitPyCharm会自动识别.idea/配置开箱即用。添加Add与提交Commit当修改了test1.air脚本例如修复了一个坐标偏移问题流程如下1. 在PyCharm右下角点击Git → Commit2. 勾选变更文件suite/test1.air、suite/test1.py3. 输入提交信息如fix: 修正CBA入口在小米12上的坐标偏移4. 点击Commit and Push。推送PushPyCharm会弹出推送窗口确认远程分支通常是origin/main点击Push。几秒后代码同步到GitHub。注意.gitignore已预置关键规则Airtest生成的临时文件*.tmppycache/.DS_Store日志和报告目录不提交运行产物log/report/PyCharm用户配置避免覆盖他人设置.idea/workspace.xml.idea/tasks.xml 这确保每次git status只看到真正的代码变更而非杂乱的临时文件。团队协作的黄金实践是所有脚本修改必须附带截图验证。例如当你调整了test1.air中“CBA”图像模板必须在suite/目录下新增test1_cba_fix_demo.png并在提交信息里注明“对比图见test1_cba_fix_demo.png”。这样其他成员一眼就能理解修改意图避免“这个坐标为什么是0.12”的无效讨论。5. 常见问题与排查技巧实录那些文档里不会写的血泪经验5.1 设备连接类问题90%的“运行失败”其实和脚本无关问题1“airtest run 报错 adb server is out of date”这是ADB版本冲突。Airtest自带ADB位于airtest/core/android/static/adb/但系统PATH里可能有旧版ADB。解决方案在PyCharm Terminal中执行adb version若显示1.0.32或更低则卸载系统ADB或在myRunner.py中强制指定Airtest ADB路径import os os.environ[ANDROID_HOME] path/to/airtest/core/android/static/adb/win # Windows # 或 os.environ[ANDROID_HOME] path/to/airtest/core/android/static/adb/mac # Mac问题2“iOS设备连接失败提示Could not connect to lockdownd”这是iOS信任证书问题。在Mac上打开钥匙串访问→ 左侧选择系统→ 右键锁屏证书 →显示简介→信任→始终信任。然后重启ideviceinstaller服务brew services restart ideviceinstaller。问题3“截图总是黑屏或花屏”安卓设备需开启开发者选项→USB调试安全设置→允许模拟位置部分厂商如华为需额外开启。iOS设备需在设置 → 隐私与安全性 → 分析与改进 → 共享iPhone分析开启。5.2 脚本执行类问题从“点不到”到“断言飘”全解析问题4“exists()总是返回False但截图明明有”Airtest图像匹配对亮度、对比度敏感。实测发现直播吧App在暗色模式下“数据”Tab文字变灰原模板匹配率暴跌。解决方案在Template()中增加threshold参数从默认0.7降到0.6exists(Template(rtpl1712345678901.png, threshold0.6))或用cv2预处理截图import cv2 img cv2.imread(tpl1712345678901.png, cv2.IMREAD_GRAYSCALE) img cv2.equalizeHist(img) # 直方图均衡化增强对比度 cv2.imwrite(tpl_enhanced.png, img)问题5“OCR识别‘CBA’失败返回空”Airtest OCR在小字体、抗锯齿文字上效果差。直播吧App的“CBA”是12px无衬线字体。解决方案放大截图区域再OCRsnapshot(cba_region.png, region[500, 1200, 800, 1400]) # 放大截取 pos text(CBA, threshold0.85, langeng) # 提高阈值指定英文问题6“断言比赛数据时偶尔少1条不稳定”这是典型的异步加载问题。sleep(5)不够可靠。正确做法是用poco.wait_for_any()等待多个元素from poco.utils.simplerpc import simplerpc cards poco(android.widget.LinearLayout).children() poco.wait_for_any(cards[:3], timeout10) # 等待前3个卡片任意一个出现5.3 报告与调度类问题让报告真正“可用”问题7“summary.html里点击用例名打不开log.html”路径错误。Airtest生成的log.html路径是相对路径而summary.html在report/目录下。解决方案在generate_report()中将log_html路径转换为相对summary.html的路径# 假设 log_html /Users/xxx/zhibo8/log/test1_20240521/log.html # summary.html 在 /Users/xxx/zhibo8/report/summary.html # 则相对路径为 ../log/test1_20240521/log.html rel_path os.path.relpath(log_html, os.path.dirname(summary_path))问题8“并行执行时report目录里多个用例的截图混在一起”这是myRunner.py未隔离截图目录导致。修复方法在run_single_test()中将Airtest的截图保存到用例专属目录# 在cmd中添加 --screenshot-dir 参数 cmd.extend([--screenshot-dir, test_log_dir])以下为高频问题速查表问题现象根本原因快速解决方案经验备注ModuleNotFoundError: No module named airtestPyCharm解释器未绑定Airtest环境Settings → Python Interpreter → Add System Interpreter → 选Python 3.9路径 → Install airtest务必确认Terminal中which python路径一致exists() always returns False图像模板与实际屏幕亮度/缩放不匹配降低threshold至0.5~0.6或用cv2.equalizeHist()预处理模板直播吧App在OLED屏上文字发虚需模板增强iOS连接失败Could not connect to lockdowndiOS信任证书未授权钥匙串中锁屏证书设为“始终信任”重启ideviceinstaller每次iOS系统升级后需重新操作summary.html点击无响应log.html路径为绝对路径在generate_report()中用os.path.relpath()转为相对路径绝对路径在不同机器上必然失效并行执行时截图覆盖Airtest默认截图目录全局唯一在subprocess.Popen命令中添加--screenshot-dir [test_log_dir]这是myRunner.pyv1.2修复的关键点最后分享一个小技巧在myRunner.py顶部加入环境检测函数每次运行前自动校验def check_env(): 检查必备环境 # 检查ADB if not shutil.which(adb): raise RuntimeError(ADB未安装或未加入PATH请安装Android SDK Platform-Tools) # 检查设备连接 if not os.popen(adb devices | grep -v List of devices | grep device).read().strip(): raise RuntimeError(未检测到已连接的安卓设备请检查USB调试) # 检查Airtest版本 import airtest if airtest.__version__ ! 1.3.3: raise RuntimeError(fAirtest版本应为1.3.3当前为{airtest.__version__}请pip install airtest1.3.3)这个函数让所有环境问题在脚本执行第一行就暴露避免跑完20分钟才发现设备没连上——这才是生产级脚本该有的脾气。本文还有配套的精品资源点击获取简介直接跑通直播吧App的UI自动化测试流程包含两个真实可用的.air脚本test1.air、test2.air走通‘数据’→‘CBA’核心操作路径用myRunner.py统一控制执行方式支持串行或并行批量运行每次执行完自动生成summary.html聚合报告点进任一失败用例就能立刻看到对应日志和截图问题定位不绕弯项目结构开箱即用含suite测试集目录、log日志输出、report报告生成、.idea配置和Git提交指引requirements.txt已列好依赖PyCharm里配好Airtest环境就能调试运行所有代码在本地验证通过配套说明覆盖环境配置、脚本运行、GitHub克隆/添加/提交/推送全流程压缩包里还有.gitignore、init.py、模板文件和原始资源目录拿来就能改、就能测、就能交。本文还有配套的精品资源点击获取