在APP自动化测试实践中,测试人员普遍会遇到一类典型问题:部分页面元素缺乏固定的id、xpath等可定位属性,例如自定义弹窗内的文本按钮、动态生成的验证码文本,或是部分原生控件的属性被开发屏蔽,导致常规元素定位方法失效。仅依赖Airtest的图像识别能力,在文字内容变化但样式一致的场景下,识别精准度往往难以满足测试需求。
光学字符识别(OCR)技术可有效解决此类问题。本文将探讨如何将PaddleOCR集成至Airtest框架,借助OCR能力增强APP自动化测试效果,攻克常规定位方法无法解决的技术难点。
一、先搞定环境:Airtest + PaddleOCR 安装
在开始写代码之前,先把基础环境搭好。这里要注意版本兼容性,不然容易踩坑。咱们先明确需要安装的核心依赖包,再一步步操作。
1.1 基础环境要求
-
Python 3.8.6(必须严格遵守,避免版本差异导致的问题)
-
Windows/macOS/Linux均可,建议Windows(对Airtest的GUI工具支持更友好)
-
手机或模拟器(确保开启开发者模式,USB调试已打开)
1.2 依赖包安装
先创建一个虚拟环境(避免污染全局环境,这是好习惯),然后安装对应的依赖包。直接用pip安装即可,注意指定合适的版本:
python
# 创建并激活虚拟环境(Windows示例)
python -m venv ocr_auto_test_env
ocr_auto_test_env\Scripts\activate
# 安装Airtest,指定1.2.7版本(稳定且兼容Python3.8)
pip install airtest==1.2.7
# 安装PaddleOCR,指定2.6.1.3版本(避免最新版本的兼容性问题)
pip install paddleocr==2.6.1.3
# 安装Airtest配套的Android控制依赖(如果测Android APP)
pip install pocoui==1.0.82
注意事项:
安装PaddleOCR时,会自动安装PaddlePaddle依赖,无需额外手动安装;
如果是macOS系统,激活虚拟环境的命令是:source ocr_auto_test_env/bin/activate;
若安装过程中出现权限错误,Windows可右键命令行以管理员身份运行,macOS/Linux在命令末尾加--user。
1.3 环境验证
安装完成后,咱们简单验证一下环境是否可用:
python
# 验证Airtest
from airtest.core.api import *
print("Airtest导入成功")
# 验证PaddleOCR
from paddleocr import PaddleOCR
ocr = PaddleOCR(use_angle_cls=True, lang='ch')
print("PaddleOCR初始化成功")
运行上述代码,如果没有报错,说明基础环境已经没问题了。这里补充一个环境验证的示意图,帮助大家直观查看运行结果:

二、核心逻辑:OCR如何加持APP自动化测试?
在Airtest的常规自动化测试中,我们主要依赖图像识别(找图)和元素定位(基于Android的uiautomator2、iOS的xctest)。但遇到前面说的"无属性可定位"场景时,这两种方式就会受限。
OCR加持的核心逻辑很简单:先通过Airtest获取APP当前页面的截图,然后用PaddleOCR识别截图中的文字内容和对应坐标,最后根据识别到的文字,用Airtest的点击、输入等API操作对应位置的元素。整个流程可以总结为:截图 → 文字识别 → 坐标提取 → 自动化操作。
举个具体的场景:一个APP的弹窗提示"确认提交",这个按钮没有id,也没有固定的xpath,但是文字是固定的。我们就可以通过上述流程,识别"确认提交"这几个字的坐标,然后点击这个坐标位置,完成自动化操作。
三、实操实现:Airtest + PaddleOCR 代码编写
接下来进入实操环节,咱们以"识别APP页面文字并点击指定文字位置"为例,完整实现一套代码。先说明一下本次实操的场景:打开某款APP(以Android端的"设置"APP为例,无需额外安装,系统自带,方便大家测试),通过OCR识别"WLAN"文字并点击进入。
3.1 整体代码目录结构
本次实操是单文件代码,但为了符合多文件代码示例的规范(提前演示目录结构写法),我们先给出一个可扩展的目录结构,后续如果需要扩展功能,直接按这个结构新增文件即可:
python
ocr_app_auto_test/
├── common/ # 公共工具类目录
│ ├── __init__.py
│ └── ocr_utils.py # OCR相关工具函数
├── test_cases/ # 测试用例目录
│ ├── __init__.py
│ └── test_ocr_click.py # 测试OCR点击功能
└── run.py # 程序入口文件
3.2 核心代码实现
下面按目录结构依次编写代码,所有代码基于Python 3.8.6,不使用type hint。
3.2.1 common/ocr_utils.py(OCR工具函数)
这个文件封装PaddleOCR的初始化和文字识别功能,方便后续复用:
python
from paddleocr import PaddleOCR
from airtest.core.api import snapshot
# 初始化PaddleOCR,全局只初始化一次,避免重复加载模型耗时
ocr = PaddleOCR(use_angle_cls=True, lang='ch', use_gpu=False)
def ocr_recognize_screen(save_screenshot_path=None):
"""
对当前APP页面截图,并用OCR识别文字和坐标
:param save_screenshot_path: 截图保存路径,None则不保存
:return: OCR识别结果,格式为列表,每个元素是(文字, 坐标, 置信度)
"""
# 1. 用Airtest获取当前页面截图
if save_screenshot_path:
snapshot(filename=save_screenshot_path)
img_path = save_screenshot_path
else:
# 临时截图,保存到默认路径
img_path = snapshot()
# 2. 用PaddleOCR识别截图中的文字
result = ocr.ocr(img_path, cls=True)
# 3. 解析识别结果,提取文字和对应坐标(取文字区域的中心坐标)
recognize_result = []
for line in result:
for word_info in line:
text = word_info[1][0]
# 坐标格式:[[x1,y1],[x2,y2],[x3,y3],[x4,y4]],取中心坐标
x1, y1 = word_info[0][0]
x3, y3 = word_info[0][2]
center_x = (x1 + x3) / 2
center_y = (y1 + y3) / 2
confidence = word_info[1][1]
recognize_result.append((text, (center_x, center_y), confidence))
return recognize_result
def find_text_coordinate(recognize_result, target_text, min_confidence=0.8):
"""
从OCR识别结果中找到目标文字的中心坐标
:param recognize_result: ocr_recognize_screen的返回结果
:param target_text: 目标文字
:param min_confidence: 最小置信度,低于此值的结果忽略
:return: 目标文字的中心坐标(x,y),未找到返回None
"""
for text, coordinate, confidence in recognize_result:
if target_text in text and confidence >= min_confidence:
return coordinate
return None
3.2.2 test_cases/test_ocr_click.py(测试用例)
编写具体的测试用例,实现"打开设置APP → 识别WLAN文字 → 点击进入"的流程:
python
from airtest.core.api import *
from airtest.core.android import Android
from common.ocr_utils import ocr_recognize_screen, find_text_coordinate
def test_ocr_click_wlan():
# 1. 连接Android设备(确保设备已通过USB连接,开启USB调试)
# 这里不指定设备号,默认连接第一个已连接的设备
dev = Android()
connect_device("Android:///")
print("设备连接成功")
# 2. 打开设置APP(包名:com.android.settings,启动Activity:.Settings)
start_app("com.android.settings")
print("设置APP启动成功")
# 等待页面加载完成
sleep(2)
# 3. 对当前页面进行OCR识别,保存截图到当前目录
recognize_result = ocr_recognize_screen(save_screenshot_path="settings_home.png")
print("OCR识别完成,识别结果:", recognize_result)
# 4. 查找目标文字"WLAN"的坐标
target_coordinate = find_text_coordinate(recognize_result, "WLAN")
if target_coordinate:
print(f"找到目标文字'WLAN',坐标:{target_coordinate}")
# 5. 点击目标坐标
touch(target_coordinate)
print("点击WLAN成功")
# 等待页面跳转
sleep(2)
# 再次截图,验证是否跳转成功
snapshot(filename="wlan_page.png")
print("跳转后截图已保存")
else:
print(f"未找到目标文字'WLAN'或置信度不足")
# 6. 关闭APP
stop_app("com.android.settings")
print("设置APP关闭成功")
# 7. 断开设备连接
dev.disconnect()
print("设备连接断开")
if __name__ == "__main__":
test_ocr_click_wlan()
3.2.3 run.py(程序入口)
编写入口文件,用于执行测试用例:
python
from test_cases.test_ocr_click import test_ocr_click_wlan
if __name__ == "__main__":
print("开始执行OCR加持的APP自动化测试用例")
test_ocr_click_wlan()
print("测试用例执行完成")
3.3 代码运行说明
-
运行前准备:确保Android设备已通过USB连接电脑,开启开发者模式和USB调试;如果用模拟器,确保模拟器已启动,且与电脑正常连接。
-
运行命令:在项目根目录下,激活虚拟环境后,执行命令:python run.py
-
运行结果:程序会自动连接设备、启动设置APP、识别WLAN文字并点击,最后关闭APP。运行过程中会生成两个截图文件:settings_home.png(设置首页截图)和wlan_page.png(WLAN页面截图),同时控制台会输出相关日志信息。
四、使用注意事项
在实际使用Airtest + PaddleOCR进行APP自动化测试时,有几个点需要特别注意,避免出现问题:
4.1 模型加载与性能问题
PaddleOCR的模型首次加载时会比较耗时,建议全局只初始化一次(就像我们在ocr_utils.py里做的那样),不要在每次识别时都重新初始化,否则会严重影响测试效率。如果测试环境有GPU,可以开启use_gpu=True,能显著提升识别速度。
4.2 置信度阈值的设置
不同的APP页面、不同的文字清晰度,OCR识别的置信度会有差异。如果置信度阈值设置太低,容易识别错误;设置太高,可能会找不到目标文字。建议根据实际测试场景调整min_confidence参数,一般设置在0.7-0.9之间比较合适。
4.3 截图质量的影响
OCR识别的准确率很大程度上依赖于截图质量。如果APP页面有模糊、反光、遮挡等情况,识别效果会很差。建议在测试时确保设备屏幕干净、无遮挡,同时避免在页面加载过程中截图(可以通过sleep等待页面加载完成,或者用Airtest的wait函数)。
4.4 多文字重复的场景处理
如果页面中有多个相同的目标文字,find_text_coordinate函数会返回第一个识别到的坐标。如果需要点击特定位置的文字,需要扩展函数逻辑,比如根据坐标的范围来筛选(比如只点击屏幕上半部分的目标文字)。
4.5 平台兼容性问题
本次实操是基于Android平台,iOS平台的使用方式类似,但需要注意Airtest对iOS的支持要求:需要安装Xcode、配置WebDriverAgent等。另外,PaddleOCR在iOS平台的性能表现可能不如Android,建议在iOS测试时多做验证。
五、总结
OCR技术为解决APP自动化测试中的元素定位难题提供了一种有效的思路,尤其是在处理无固定属性的元素、动态文字等场景时,Airtest的图像识别能力结合PaddleOCR的文字识别能力,能极大地提升自动化测试的覆盖率和稳定性。