Android APP 自动化测试教程(Uiautomator2 + Airtest )
本文介绍了一个基于Python + Pytest + Allure的Android APP混合驱动自动化测试框架搭建教程。该框架结合了Uiautomator2的原生控件定位能力和Airtest的图像识别技术,适用于复杂UI场景的测试。教程详细讲解了环境配置步骤,包括ADB工具、Python 3.9、JDK 8、PyCharm等必备软件的安装,以及Airtest IDE、Weditor等辅助工具的使
·
Android APP 自动化测试教程 (混合驱动版)
本教程介绍如何搭建基于 Python + Pytest + Allure 的测试框架。
核心策略:使用 Uiautomator2 进行高效的原生控件定位(文字、ID),使用 Airtest 处理复杂的自定义 UI 或图标识别。
1. 安装 Android 调试工具 (ADB)
- 下载
platform-tools.zip(见附件或 官网下载)。 - 解压并配置环境变量
Path指向解压目录。 - 终端执行
adb --version验证安装。
2. 安装 Python 3.9
- 推荐版本:Python 3.8 或 3.9。
- python安装参考:python安装教程
- 环境管理:建议安装
pipenv。pip install pipenv
3. 安装 JDK 8
- 用于 Allure 报告生成,必须安装 JDK 1.8。
- 安装后执行
java -version验证。
jdk安装教程参考:jdk8安装教程
4. 安装 PyCharm
- 建议安装 PyCharm Community 免费版。
安装教程参考:pycharm安装教程
5. 安装辅助工具
Airtest IDE
- 用于截图和录制,获取图片代码。
- 下载地址
Weditor (推荐配合 Uiautomator2)
- 用于查看原生控件属性 (Resource-ID, XPath)。
- 安装命令:
pip install weditor - 启动命令:
python -m weditor
6. 安装 Allure
- 下载并配置 Allure 命令行工具,确保
bin目录在环境变量中。 - 验证:
allure --version。 - 安装参考:安装配置allure教程
7. 项目依赖安装 (必做)
在项目根目录下,使用终端安装以下库:
# 1. 创建虚拟环境 (可选,如果不使用虚拟环境直接跳过此行)
pipenv install --python 3.9
# 2. 安装自动化核心库
# uiautomator2: 原生元素定位
# airtest: 图像识别
# pytest: 测试框架
# allure-pytest: 报告插件
pip install uiautomator2 airtest pytest allure-pytest
首次连接手机前,需初始化 uiautomator2 守护程序:
python -m uiautomator2 init
8. 完整代码示例 (直接复制)
新建一个 Python 文件(例如 test_hybrid_demo.py),内容如下。该代码封装了两种查找方式,并演示了如何在一个测试类中同时使用它们。
import os
import time
import logging
import pytest
import allure
import uiautomator2 as u2
from uiautomator2._selector import UiObject
from airtest.core.api import *
from airtest.core.error import TargetNotFoundError
# ==================== 1. 全局配置 ====================
# 配置日志格式
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
DEFAULT_TIMEOUT = 10
# ==================== 2. 核心封装函数 ====================
def take_screenshot(name_suffix):
"""
截图并附加到 Allure 报告中
"""
try:
# 使用 Airtest 的截图功能
filename = f"err_{int(time.time())}_{name_suffix}.png"
snapshot(filename=filename, msg=name_suffix)
if os.path.exists(filename):
with open(filename, "rb") as f:
allure.attach(f.read(), name=name_suffix, attachment_type=allure.attachment_type.PNG)
# 截图后可选择删除本地文件,保持目录整洁
# os.remove(filename)
except Exception as e:
logging.error(f"截图失败: {e}")
def find_image(
image: Template,
expected_found=True,
should_log_errors=True,
timeout=DEFAULT_TIMEOUT,
) -> bool:
"""
【Airtest】基于图像识别查找
"""
try:
# 尝试等待图片出现
wait(image, timeout=timeout)
real_found = True
except TargetNotFoundError:
real_found = False
# 异或逻辑:如果期望值与实际值不一致,则结果为 False
result = not (expected_found ^ real_found)
if not result and should_log_errors:
if expected_found:
logging.error(f"未找到图片元素({image.filename}),预期应存在")
else:
logging.error(f"找到了图片元素({image.filename}),预期不应存在")
take_screenshot(os.path.basename(image.filename))
return result
def find_uiobject(
ui_object: UiObject,
object_name: str,
wait_timeout=DEFAULT_TIMEOUT,
expected=True,
) -> bool:
"""
【Uiautomator2】基于属性定位查找
"""
# 1. 判断元素实际是否存在
if expected:
# wait() 返回 True 表示找到,False 表示超时
real_found = ui_object.wait(timeout=wait_timeout)
else:
# wait_gone() 返回 True 表示消失了(即不存在),False 表示还在(即存在)
is_gone = ui_object.wait_gone(timeout=wait_timeout)
real_found = not is_gone
# 2. 对比预期结果
result = not (expected ^ real_found)
# 3. 错误处理与日志
if not result:
if expected:
logging.error(f"未找到控件元素({object_name}),预期应存在")
else:
logging.error(f"找到了控件元素({object_name}),预期不应存在")
# 处理文件名非法字符
safe_name = object_name.replace(":", "").replace("/", "_").replace(" ", "")
take_screenshot(safe_name)
return result
# ==================== 3. 测试用例类 ====================
@allure.feature("混合驱动自动化测试Demo")
class TestHybridApp:
d = None # Uiautomator2 设备对象
def setup_class(self):
"""
初始化:同时连接 Airtest 和 Uiautomator2
"""
logging.info("正在初始化设备连接...")
# 1. 初始化 Airtest (用于图像识别)
# devices=["Android:///"] 自动连接本地第一台安卓设备
auto_setup(__file__, logdir=True, devices=["Android:///"])
# 2. 初始化 Uiautomator2 (用于属性定位)
self.d = u2.connect()
# 3. 启动测试App (这里以Android原生设置为例)
# 请替换为你自己的包名,例如: self.d.app_start("com.tencent.mm")
self.d.app_start("com.android.settings")
# 简单等待启动动画结束
time.sleep(2)
def teardown_class(self):
"""
清理:关闭App
"""
self.d.app_stop("com.android.settings")
@allure.story("属性查找测试")
@allure.title("使用 Uiautomator2 查找文字")
def test_find_by_prop(self):
"""
测试用例:验证设置页面的 'WLAN' 选项存在
"""
# 步骤1:定义选择器 (Uiautomator2)
# 支持 text, resourceId, description 等
wlan_obj = self.d(text="WLAN")
# 步骤2:执行断言
is_found = find_uiobject(
ui_object=wlan_obj,
object_name="WLAN菜单项",
expected=True
)
assert is_found, "断言失败:未在设置页面找到 WLAN 文字"
# 步骤3:执行操作
if is_found:
wlan_obj.click()
logging.info("点击成功")
@allure.story("图像查找测试")
@allure.title("使用 Airtest 查找图标")
def test_find_by_image(self):
"""
测试用例:使用图像验证页面元素
注意:运行此用例前,请使用AirtestIDE截图并保存为 'tpl_icon.png'
"""
# 模拟:回到设置主页
self.d.app_start("com.android.settings")
time.sleep(1)
# 步骤1:定义图片模板 (Airtest)
# 实际使用时,请确保当前目录下有这张截图
target_img = Template(r"tpl_icon.png", record_pos=(0, 0), resolution=(1080, 2400))
# 这里的判断是为了演示,防止你没有截图导致直接报错
if not os.path.exists("tpl_icon.png"):
logging.warning("提示:当前目录缺少 tpl_icon.png,跳过图像识别实际执行")
return
# 步骤2:执行断言
is_found = find_image(
image=target_img,
expected_found=True
)
assert is_found, "断言失败:未通过图像识别找到指定图标"
@allure.story("异常测试")
@allure.title("验证元素不存在的情况")
def test_not_exist(self):
"""
验证一个不存在的 ID,预期结果为 '找不到'
"""
fake_obj = self.d(resourceId="com.android.settings:id/fake_id_12345")
is_found = find_uiobject(
ui_object=fake_obj,
object_name="不存在的ID",
wait_timeout=3,
expected=False # 重点:我们期望它不存在
)
assert is_found, "断言失败:本不该存在的元素出现了"
if __name__ == "__main__":
# 执行命令:pytest -s -v test_hybrid_demo.py --alluredir=./report
pytest.main(["-s", "-v", "test_hybrid_demo.py", "--alluredir=./report/xml"])
9. 运行测试与生成报告
-
运行脚本:
在 PyCharm 终端执行:pytest test_hybrid_demo.py --alluredir=./report/xml -
查看报告:
测试完成后,执行:allure serve ./report/xml
需要学习相关知识文档
airtest(只看Android和IOS相关的):airtest官方用户手册
pytest:pytest官方文档
pytest快速上手教程
更多推荐

所有评论(0)