本文还有配套的精品资源,点击获取
简介:直接跑通直播吧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()都配了timeout=15和自定义错误信息。这不是为了炫技,是因为直播吧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锁死airtest==1.3.3(避开了1.3.4里已知的iOS截图截断bug),log/和report/目录设为PyCharm忽略项防止误提交,连.gitignore里都预置了__pycache__/、.DS_Store和Airtest生成的临时.tmp文件。它不是一个教学玩具,而是一套拧上螺丝就能运转的测试产线模块。
2. 整体架构与设计思路:为什么是Airtest+PyCharm+HTML聚合,而不是Appium+Jenkins?
很多人看到“UI自动化”,第一反应是Appium+Java+Maven+Jenkins,配置一套下来三天起步,光是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(r"tpl1712345678901.png", record_pos=(0.12, -0.34), resolution=(1080, 2340)))改成touch(Template(r"tpl1712345678901.png", record_pos=(0.12, -0.34), resolution=(1080, 2340)), timeout=15),加一行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.py,3分钟出报告,截图发群里@开发。这个流程里,Jenkins带来的自动化收益远低于它引入的维护成本。我们把复杂性压在了myRunner.py的代码里(总共287行),而不是压在运维环境里。未来如果日构建量涨到50+用例,再平滑迁移到GitHub Actions——用actions/setup-python@v4装依赖,actions/checkout@v4拉代码,最后python myRunner.py --mode parallel,整个CI配置文件不超过15行。这种渐进式演进,比一开始堆砌重型工具更符合实际。
整个工程包的目录结构,每一层都在回答一个协作问题:suite/目录明确告诉所有人“这里放测试用例,别乱扔”;log/和report/分离,确保原始日志可追溯,聚合报告可分享;.idea/里预置了workspace.xml(含Airtest插件启用状态)和misc.xml(含Python SDK路径),新同事克隆代码后双击myRunner.py就能Debug;requirements.txt里airtest==1.3.3和pocoui==1.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.16(Mac/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.9;Windows示例: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 python(Mac/Linux)或where python(Windows),路径必须与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(r"tpl1712345678901.png", record_pos=(0.0, -0.75), resolution=(1080, 2340))): touch(Template(r"tpl1712345678901.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(timeout=15) data_tab.click() sleep(2) except PocoTargetTimeout: # OCR兜底:截全屏,用Airtest OCR识别"数据"文字坐标 snapshot("temp_fullscreen.png") pos = text("数据", threshold=0.7) # Airtest OCR接口 if pos: touch(pos) sleep(2) else: raise Exception("无法定位'数据'Tab") # 步骤3:在列表中找到"CBA"并点击 # 图像匹配 + OCR双保险 cba_img = Template(r"tpl1712345678902.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", threshold=0.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(f"android.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, f"CBA页仅找到{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_ok=True) # 构建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, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, cwd=os.path.dirname(test_path) ) stdout, _ = proc.communicate(timeout=300) # 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.超时熔断:timeout=300强制5分钟内结束,防止某个用例卡死拖垮整个批次。返回TIMEOUT状态,便于报告中高亮。
myRunner.py的并行模式实际是concurrent.futures.ThreadPoolExecutor实现:
def run_parallel(tests: List[str], device: str, max_workers: int = 3): """并行执行测试集""" with ThreadPoolExecutor(max_workers=max_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_workers=3不是拍脑袋定的。我们在华为P30(8GB内存)上实测:设为4时,Airtest进程频繁OOM崩溃;设为2时,5个用例总耗时12分钟;设为3时,总耗时8分钟且零崩溃。这个数字是硬件资源与Airtest内存占用的精确平衡点。
4. 实操过程与核心环节实现:从克隆代码到生成报告的全流程手把手
4.1 本地环境一键初始化:5分钟完成从零到可运行
假设你已安装Python 3.9和PyCharm,以下是完整初始化流程(Windows/Mac通用):
步骤1:克隆代码仓库
打开PyCharm,File → New → Project from Version Control,VCS选择Git,URL粘贴你的仓库地址(如https://github.com/yourname/zhibo8-airtest.git),Directory选择本地存放路径(如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设备:需提前配置WebDriverAgent(WDA)。参考官方文档,确保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 class="table"> {% for case in cases %} <tr class="case-row {{ case.status|lower }}"> <td>{{ loop.index }}</td> <td><a 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 }}" width="100" height="120" alt="screenshot"> </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.git,PyCharm会自动识别.idea/配置,开箱即用。
添加(Add)与提交(Commit):当修改了test1.air脚本,例如修复了一个坐标偏移问题,流程如下:
1. 在PyCharm右下角点击Git → Commit;
2. 勾选变更文件(suite/test1.air、suite/test1.py);
3. 输入提交信息,如fix: 修正CBA入口在小米12上的坐标偏移;
4. 点击Commit and Push。
推送(Push):PyCharm会弹出推送窗口,确认远程分支(通常是origin/main),点击Push。几秒后,代码同步到GitHub。
注意:
.gitignore已预置关键规则:
```Airtest生成的临时文件
*.tmp
pycache/
.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.6:
exists(Template(r"tpl1712345678901.png", threshold=0.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无衬线字体。解决方案:放大截图区域再OCR:
snapshot("cba_region.png", region=[500, 1200, 800, 1400]) # 放大截取 pos = text("CBA", threshold=0.85, lang="eng") # 提高阈值,指定英文问题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], timeout=10) # 等待前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 'airtest' | PyCharm解释器未绑定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 lockdownd | iOS信任证书未授权 | 钥匙串中锁屏证书设为“始终信任”,重启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(f"Airtest版本应为1.3.3,当前为{airtest.__version__},请pip install airtest==1.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、模板文件和原始资源目录,拿来就能改、就能测、就能交。
本文还有配套的精品资源,点击获取