鸿蒙-Hypium自动化(Python版本)
鸿蒙-Hypium自动化(Python版本)
前言
DevEco Testing Hypium (以下简称Hypium)是HarmonyOS平台的UI自动化测试框架,支持用户使用Python语言为应用编写UI自动化测试脚本,主要包含以下特性:
- Hypium提供了控件、图像和比例坐标等多种控件定位能力,支持多窗口操作以及触摸屏/鼠标/键盘等多种模拟输入功能,支持多设备并行操作,能够覆盖各类场景和多种形态设备上的自动化用例编写需求,可支持鸿蒙手机、平板、PC等设备。
- Hypium提供了在PyCharm中使用的用例编写辅助插件,支持控件查看/投屏操作等多种用例开发辅助功能,提升用例开发体验和效率。
- Hypium能够为执行的用例生成详细的用例执行报告,并且自动记录设备日志以及执行步骤截图,为用户提供高效和专业的测试用例执行和结果分析体验。
安装向导
- 安装Python
推荐从Python官网安装Python3.10版本。 - 安装PyCharm
推荐从PyCharm官网安装2022.3以后的社区版本。 - 安装hdc
请参考调试工具-hdc中环境准备章节来安装和配置hdc环境。 - 安装Hypium
- 方式一:PyPI在线安装(推荐)
在命令行中执行以下命令安装最新版本hypium
pip install hypium -U- 方式二:安装包离线安装
访问华为开发者联盟官网下载DevEco Testing Hypium安装包。下载后解压该安装包,找到其中的hypium-6.1.0.210.zip(此版本仅作为示例,请以实际版本号为准)。再次解压hypium-6.1.0.210.zip,进入解压后的文件目录执行以下命令进行安装。
自动安装
python install.py -g hypium_basic #安装基础包,通过-g执行安装组合模式
注意
仅6.1及之后版本支持离线自动安装。
手动安装
python -m pip install xdevice-6.1.0.210-py3-none-any.whl
python -m pip install xdevice_devicetest-6.1.0.210-py3-none-any.whl
python -m pip install xdevice_ohos-6.1.0.210-py3-none-any.whl
python -m pip install hypium-6.1.0.210-py3-none-any.whl
# 此版本仅作为示例,实际请根据项目使用的版本选择- DevEco Testing Hypium插件安装及使用方法
注意
Mac系统使用UiViewer功能时,需在设置面板中手动指定hdc路径,详情可见 本小节中 · 插件功能 Ⅳ.设置面板区域-hdc路径。
若设备ROM版本和hypium都为6.1及以上版本,则UiViewer版本也需要升级至6.1及以上版本,否则在用例执行过程中,UiViewer会出现断连现象。
- 插件安装
Ⅰ. 访问华为开发者联盟官网下载页面下载DevEco Testing Hypium安装包,下载后解压该安装包,找到其中的hypium-pycharm-plugin-6.1.0.210.zip(该版本号仅做示例,请以实际版本号为准),此文件为插件的安装包,无需再进行解压。
Ⅱ. 打开PyCharm后,点击File -> Settings -> Plugin -> 齿轮图标 -> Install Plugin from Disk。在弹出的文件选择器中,选择第一步下载的hypium-pycharm-plugin-6.1.0.210.zip(该版本号仅做示例,请以实际版本号为准)离线安装包,完成安装。安装完成后,重启PyCharm即可使用新安装的Deveco Testing Hypium插件。
说明在6.0及以后的版本中,DevEco Testing Hypium插件在下载包中的名称由“DevEcoTesting-Hypium”修改为“hypium-pycharm-plugin”。

安装完成后在Plugins界面可以看到DevEcoTesting-Hypium插件。
- 插件功能
PyCharm有三个主要的开发功能区,如下图所示。DevEco Testing Hypium插件在不同的开发功能区提供了对应的用例开发辅助功能,在PyCharm的设置面板中提供了插件的设置功能,在PyCharm的工程新建面板中提供了用例工程模板创建功能,下文分区域介绍这些功能。
Ⅰ. 项目文件区域
在项目文件区域右键点击项目目录或者文件,选择 DevEco Testing Hypium,弹出对应的功能菜单。
功能菜单根据选择的目录和文件不同存在区别,详细参见下表:
点击图片可查看完整电子表格
生成 DevEco Testing 工具 可用的 测试服务包 ,需要补充以下两个文件。
setup-regression.py 文件补充
from setuptools import setup
setup(
#测试服务包名称
name='hypium-perf-test',
# 测试服务包版本
version='1.0.0',
# 作者
author='dengjiajun',
py_modules=['testcases.Example'], # 指定测试用例文件列表
include_package_data=True,
)MANFEST.in 配置文件补充
include testcases/Example.json
include aw/*.py
include config/*.xml
include resource/*Ⅱ. 代码编辑区域
点击图片可查看完整电子表格
Ⅲ. ToolWindow区域
UiViewer功能
DevEco Testing Hypium插件会在PyCharm界面右边缘的ToolWindow区域生成UiViewer标签,点击后会展开UiViewer功能面板。UiViewer功能目前分为4个界面:设备选择界面 、单设备控件查看界面 、单设备投屏界面 、双设备投屏界面。
注意
UiViewer插件当前仅支持USB连接本地设备调测和本地模拟器进行调测,但是由于模拟器性能资源管理策略,当模拟器处于后台或被其他页面遮挡时,将不会进行画面渲染绘制。此时在投屏时会出现黑屏闪烁现象,如需规避,需要使模拟器处于前台显示。
设备选择界面
设备选择界面如下图所示, 若首次进入该界面,或设备状态发生变化,需点击“刷新”按钮以更新设备列表。
设备信息说明见下表:
点击图片可查看完整电子表格
设备选择界面最多支持同时选择两个设备进行投屏。
- 若仅勾选一个设备并点击“确定”按钮,则进入单设备投屏界面。
- 若勾选了两个设备并点击“确定”按钮,将进入双设备投屏界面;其中,设备编号为 “dev1” 的设备显示在左侧,设备编号为 “dev2”的设备显示在右侧,用户可以通过设备编号的下拉选项框自定义配置设备编号,控制双设备投屏。
单设备投屏界面
功能说明: - 设备切换按钮:点击后返回设备选择界面,可重新选择要投屏的设备。
- 设备屏幕显示区域:显示当前设备的实时屏幕画面。在投屏模式下,可通过鼠标点击或滑动该界面来操作设备。
- 工具区:位于设备屏幕显示区域右侧,从上至下分为以下三个子工具区。
工具区1:
该工具区提供控件查看功能。进入控件查看模式后,设备画面将保持静止,不再实时更新。若需获取当前页面的最新控件信息,需手动点击“控件刷新”按钮以重新抓取页面结构和控件数据。
点击图片可查看完整电子表格
工具区2:
此工具区提供一系列常用的设备操作功能,便于在投屏过程中快速执行基本控制与调试操作,当前支持的功能见下表:
点击图片可查看完整电子表格
工具区3:
此工具区提供系统管理相关功能,当前支持的功能见下表:
点击图片可查看完整电子表格
双设备投屏界面
该界面支持同时对两个设备进行投屏与操作,双设备投屏时,每个设备的显示区域功能与单设备投屏一致,支持独立触摸控制、截图、旋转等操作。
当需要对某一设备进行控件查看时,插件将自动退出双设备投屏模式,切换至单设备控件查看界面,以确保控件信息的准确展示与操作体验。完成控件查看后,用户可手动返回双设备投屏视图。
执行结果报告展示功能
使用“一键执行当前用例”功能完成测试用例执行后,插件将在控制台旁边自动生成执行结果标签。点击该标签,即可查看本次用例执行过程中各步骤的截图。
Ⅳ. 设置面板区
打开PyCharm设置面板,选中左侧的DevEco Testing Hypium选项,可以进入DevEco Testing Hypium的设置面板,如下图所示。
各个配置项的详细说明见下表:
点击图片可查看完整电子表格
Ⅴ. 工程创建区域
在PyCharm顶部点击File -> New Project 进入模板工程创建面板。
点击左侧的DevEco Testing Hypium,可以创建Hypium用例模板工程。共有两种类型的Hypium模板工程,分别对应单设备和双设备的测试场景。
建议使用 python 3.10 及以上,因为导出测试服务包 需要 3.10 以上
选择对应模板,配置工程路径以及Python环境参数,点击Create即可创建Hypium测试用例工程。工程目录中包含一个模板用例和一个模板配置文件user_config.xml。
以单设备工程为例,创建完成后的界面如下图所示。连接被测设备后,可右键点击模板用例文件代码编辑区域“执行hypium用例”来运行当前用例。
测试脚本开发快速入门
本章节将指导用户创建并执行一个简单的测试脚本工程,快速掌握项目目录结构中的关键文件,熟悉基于Hypium的测试脚本开发流程。
测试脚本工程创建
测试脚本工程创建主要有两种方式:
a)直接使用以下附件中的模板工程。
HypiumProjectTemplate.zip
b)通过PyCharm上的DevEcoTesting-Hypium插件进行创建。请参考本文档的“安装向导 -> DevEco Testing Hypium插件安装及使用方法 -> 插件功能 -> 工程创建区域”小节。
Ⅰ.工程目录文件介绍
HypiumProjectTemplate
| |----aw // 工程中自定义模块文件夹
| | |----Utils.py // 示例模块文件
| |----config // 测试工程配置文件夹
| | |----user_config.xml // 测试工程配置文件
| |----resource // 测试资源文件夹,测试过程中用到的资源文件默认会优先从当前文件夹进行查找。
| |----testcases // 测试用例文件夹,测试过程中的测试用例文件优先会从当前文件夹进行查找。
| | |----Example.json // Example测试用例配置文件,配置用例所需设备等参数。
| | |----Example.py // Example测试用例文件,存储测试逻辑代码。注意该文件无法直接运行,要通过测试框架启动后加载执行,详情参见后文测试用例执行部分。
| |----main.py // 测试用例执行入口文件,用户可以通过运行该文件启动测试任务,执行测试用例。
Ⅱ.工程配置文件介绍
<?xml version="1.0" encoding="UTF-8"?>
<user_config>
<environment>
<!-- type: 设备连接方式,仅支持设置为usb-hdc,表示使用hdc命令控制设备(默认)。 -->
<device type="usb-hdc">
<!-- ip: 远端hdc server的ip地址,ip和port为空时使用本地设备,非空时使用远端设备。 -->
<!-- port: 远端hdc server的端口号 -->
<!-- sn:设备序列号,设为空时,表示所有设备均可用 -->
<info ip="" port="" sn="sn"/>
<!-- 可添加多个info标签,配置多个设备 -->
<info ip="" port="" sn="sn"/>
</device>
</environment>
<testcases>
<!-- 测试用例目录,该属性为空时默认使用当前项目下的testcases目录。 -->
<dir></dir>
</testcases>
<resource>
<!-- 测试资源文件目录,该属性为空时默认使用当前项目下的resource目录。 -->
<dir></dir>
</resource>
<!-- 用例执行日志级别,当前仅支持设置为INFO或者DEBUG,默认为INFO,如需更详细信息可设置为DEBUG。 -->
<loglevel>DEBUG</loglevel>
<devicelog>
<!-- 指定用例执行完成后自动从设备端拉取的文件目录,多个目录使用分号分隔。 -->
<dir>/data/log/tee;/data/log/test</dir>
<!-- 设置用例执行时抓取的hilog日志等级,默认值为INFO。 -->
<loglevel>DEBUG</loglevel>
<!-- 设置单个用例执行完成并抓取设备端hilog日志文件后,是否自动清空设备端的日志文件,默认值为true。-->
<clear></clear>
<!-- 设置用例执行完成后是否抓取设备端hilog日志文件,默认值为ON。注意设置为OFF时上述devicelog配置下的dir、loglevel以及clear属性不生效。 -->
<enable>ON</enable>
</devicelog>
<taskargs>
<!-- pass_through,透传参数给测试用例。如{"task_id":"950191","user_define":{"execType":"3"}} -->
<!-- 参数获取方法:from xdevice import Variables; print(Variables.config.pass_through) -->
<pass_through></pass_through>
<!-- repeat,用例重复运行多少次。大于1的整数才生效 -->
<repeat></repeat>
<!-- screenshot,操作类接口运行后是否截图。true开启/false不开启,默认值false -->
<screenshot>false</screenshot>
<!-- screenrecorder,用例Step步骤是否录屏。true开启/false不开启,默认值false -->
<screenrecorder>false</screenrecorder>
</taskargs>
</user_config>Ⅲ.测试用例介绍
Hypium 测试用例由两部分组成:测试用例配置文件(JSON 格式)和测试用例脚本文件(Python 格式)。测试用例的组织方式支持两种模式:
- 单个用例模式:包含一个测试用例脚本(Python)文件和一个测试用例配置(JSON)文件;
- 测试套模式:包含一个测试套脚本(Python)文件、多个测试用例脚本(Python)文件和一个测试套配置(JSON)文件。
用户可根据实际需求选择合适的组织方式。
单个测试用例模式
测试用例脚本文件(Example.py)
该文件包含测试用例的执行逻辑,核心为三个关键的生命周期函数:setup、process、teardown。
在用例开发时,用户需要根据业务需求在对应的函数中编写测试逻辑代码。生命周期函数的详细说明见下表:
点击图片可查看完整电子表格
示例代码
# !/usr/bin/env python
# coding: utf-8
from devicetest.core.test_case import TestCase, Step
from devicetest.utils.file_util import get_resource_path
from hypium import *
from aw import Utils
class Example(TestCase):
def __init__(self, controllers):
self.TAG = self.__class__.__name__
TestCase.__init__(self, self.TAG, controllers)
self.driver = UiDriver(self.device1)
def setup(self):
Step('1.回到桌面')
self.driver.swipe_to_home()
def process(self):
Step('2.检查短信应用版本')
mms_version = Utils.get_app_version_code(self.driver, 'com.ohos.mms')
host.check_greater(mms_version, 0)
Step('3.点击桌面上的短信')
self.driver.touch(BY.text("信息"))
def teardown(self):
Step("4. 停止短信应用")
self.driver.stop_app("com.ohos.mms")单个测试用例配置 JSON 文件
该文件主要描述测试用例的配置信息,如测试用例所需设备类型和数量、测试用例的测试驱动信息、测试用例的描述信息等。
注意:JSON文件不支持注释,请在使用示例时移除其中以 “//”开头的注释部分。
示例:
{
// description属性为测试用例的功能描述。
"description": "Config for app test suites",
// environment属性用于配置测试用例需要的设备类型和数量。
"environment": [
{
"type": "device", // 设备操作系统类型,device表示HarmonyOS设备。
"label": "phone" // 设备物理形态,phone为手机,tablet为平板,设置为空字符串或者移除该属性表示用例对设备类型无要求。用户可以通过执行hdc shell param get const.product.devicetype查看设备类型。
},
{
"type": "device", // 测试用例需要多个设备时,在environment属性中添加多个设备配置项。
"label": "phone"
}
],
// driver字段主要描述测试用例的测试驱动是什么,以及具体要执行的Python脚本文件在哪(填写与当前JSON文件的相对路径即可)
// 不填写则在当前JSON文件下寻找同名Python文件
"driver": {
"type": "DeviceTest",
"py_file": [
"Example.py"
]
}
}测试套模式
测试套脚本文件( 默认为 Ts_001.py)
该文件包含测试套的初始化和清理逻辑,核心为两个关键的生命周期函数:setup、teardown。在用例开发时,用户需要根据业务需求在对应的函数中编写测试逻辑代码。
生命周期函数的详细说明见下表:
点击图片可查看完整电子表格
注意:
使用测试套模式 启动测试用例时,
假设配置文件Json 设置的
"suitecases": [
"TC_001.py",
"TC_002.py"
]
则 该测试套件 执行的最终 顺序为:
Ts_001.py 的setup() -> TC_001.py 的setup() -> TC_001.py 的process() -> TC_001.py 的teardown() —> TC_002.py 的setup() -> TC_002.py 的process() -> TC_002的 teardown()
其实多测试用例区别不大,只需要在新建文件的时候选择Hypium TestSuite就可以自动帮我们生成多测试用例可执行的文件
- 在testcase 目录创建 测试套件


基本结构和单测试用例差不多,只不过在testcases模块变化较大,但实际上这里的json文件配置更简单
{
"environment": [
{
"type": "device",
"label": "phone"
}
],
"driver": {
"type": "DeviceTestSuite"
}
}默认可以什么都不配置,但是Ts_002.py要和json名称一样,进入Ts_002.py文件示例代码
from devicetest.core.suite.test_suite import TestSuite
from devicetest.core.test_case import Step, CheckPoint
from hypium import UiDriver, BY
class Ts_002(TestSuite):
def __init__(self, configs, path):
super().__init__(configs, path)
self.driver = None
def setup(self):
print("测试开始")
self.driver = UiDriver(self.device1)
#打开传祺App应用
Step("1.打开传祺App")
self.driver.start_app(package_name="com.cloudy.component.hos",page_name="EntryAbility")
#点击“本次使用允许”的text
#touch=self.driver.touch(BY.text("本次使用允许"))
#CheckPoint("检测点1xxxx")
def teardown(self):
print("测试结束")
#停止应用
self.driver.stop_app(package_name="com.cloudy.component.hos",wait_time=3)
#Step("收尾工作:xxxx")
# *todo*可以看到两个熟悉的函数,没错,就是整个测试过程中的周期函数,开始和结束都会执行,
测试套配置 JSON 文件( 框架默认为 Ts_002.json)
该文件主要描述测试套的配置信息,如测试套所需设备类型和数量、测试套的测试驱动信息、测试套的描述信息等。
注意:JSON文件不支持注释,请在使用示例时移除其中以 “//”开头的注释部分。
- 默认测试套
{
"environment": [
{
"type": "device",
"label": "phone"
}
],
"driver": {
"type": "DeviceTestSuite"
}
}- 自定义测试套
{
"description": "Config for OpenHarmony app test suites",
//environment字段主要描述测试用例需要的环境信息,如需要多少个设备
"environment": [
{
"type": "device",
"label": "phone"
}
],
// driver字段主要描述测试用例的测试驱动是什么,以及具体要执行的py脚本文件在哪(填写与当前json文件的相对路径即可)
"driver": {
"type": "DeviceTestSuite",
// 指定测试套配置(JSON)文件对应的测试套脚本(Python)文件路径(可省略 .py 后缀),支持相对路径或绝对路径。若使用相对路径,需相对于测试工程根目录;若未指定,则默认查找与当前 JSON 文件同目录下同名的 Python文件
"testsuite": "TS_001",
//指定测试套中的测试用例列表,有两种方式
//方式一,定义suitecases字段,然后明确定义好当前测试套下有哪些测试用例(相对路径或者是绝对路径)
"suitecases": [
"testsuite1/XXX_001.py",
"testsuite1/XXX_002.py"
]
//方式二,测试用例的py文件放在testsuite文件夹中,并且命名以"TC_"开头,框架即可自动扫描所有用例并执行
},
// kits字段主要描述测试用例需要的测试公共kit,如pushkit、shellkit等
"kits": [
]
}测试用例脚本文件(TC_001.py ; TC_002.py)
此处介绍测试用例脚本文件和测试套关联的两种方式:
方式一: 在测试套配置文件中指定所有的测试用例脚本文件路径
将测试用例脚本(Python)文件保存到测试套目录中,并且设置文件名前缀为"TC_",框架即可自动扫描当前测试套对应的所有测试用例脚本文件。
具体的测试用例文件则是TC_001这些,因为我们在json文件中没做任何配置,所以我们的测试用例必须要以TC_开头,这样在框架执行的时候,才会自动去寻找这些文件并依次执行,如果不按照这个命名规则则找不到文件,执行指令依然是
python -m hypium run -l Ts_002
当然,如果不按照这个命名规则也是可以的,但是要严格配置json文件
方式二:框架自动扫描的与测试套关联的测试用例脚本,测试用例脚本的保存目录和文件命名需要满足以下规则:
- 测试用例脚本文件需与测试套脚本文件位于同一目录。
- 测试用例脚本文件的文件名前缀是“TC_”(例如:TC_Login.py)。
测试用例执行
本章节主要介绍测试用例的执行方式。测试用例支持两种执行方式:一是通过命令行执行,二是通过 PyCharm IDE 中的DevEco Testing Hypium 插件进行一键执行。
命令介绍
Hypium框架命令可以分为三类:help、list和run。其中run为最常用的执行命令。
命令交互入口
打开命令行窗口,切换到测试脚本工程的根目录,执行以下命令可以进入Hypium控制台。
- python -m hypium
常用命令介绍
help命令
输入help指令可以查询框架指令帮助信息。
**help:**
**use help** to get information.
usage:
**run: Display** a **list** of supported run command.
**list: Display** a **list** of supported device and task record.
Examples:
**help run**
**help list**说明
help run:展示run指令相关说明;help list:展示 list指令相关说明。
list命令
list指令用来展示设备和相关的任务信息。
list:
This command **is** used to display device list and task record.
usage:
list
list history
list <id>
Introduction:
list: display device list
list history: display history record of a serial of tasks
list <id>: display history record about task what contains specific id
Examples:
list
list history
list 6e****90说明
list:展示设备信息;
list history:展示任务历史信息;
list< id >:展示特定id的任务其历史信息。
run命令
run指令主要用于执行测试任务。
run:
This command is used to execute the selected testcases.
It includes a series of processes such as use case compilation, execution, and result collection.
usage: run [-l TESTLIST [TESTLIST ...] | -tf TESTFILE
[TESTFILE ...]] [-tc TESTCASE] [-c CONFIG] [-sn DEVICE_SN]
[-rp REPORT_PATH [REPORT_PATH ...]]
[-respath RESOURCE_PATH [RESOURCE_PATH ...]]
[-tcpath TESTCASES_PATH [TESTCASES_PATH ...]]
[-ta TESTARGS [TESTARGS ...]]
[-env TEST_ENVIRONMENT [TEST_ENVIRONMENT ...]]
[--retry RETRY] [--session SESSION]
[--repeat REPEAT]
action task
Specify tests to run.
positional arguments:
action Specify action
task Specify task name,such as "ssts", "acts", "hits"run常用指令基本使用方式如下:
点击图片可查看完整电子表格
PyCharm中用例执行
PyCharm中执行用例依赖本文档的安装向导部分介绍的PyCharm插件:** DevEco Testing Hypium,请参考本文档的“安装向导 -> DevEco Testing Hypium插件安装及使用方法”小节。
测试报告查看
测试框架执行完用例后,会生成执行结果报告。报告默认存放在测试工程目录的reports目录下。如果用户在启动测试任务时通过-rp参数指定了报告路径,报告会生成在指定的路径下。
测试报告目录结构如下:
当前报告目录(默认目录/指定目录)
├── details(用例步骤截图存放目录)
├── result(模块执行结果存放目录)
│ ├── <测试用例1结果>.xml
│ ├── ... ...
├── log (设备和任务运行log存放目录)
│ ├── <测试用例1设备执行>.log
│ ├── ... ...
│ ├── <任务执行>.log
├── static (报告展示页面css元素存放目录)
├── summary_report.html(测试任务可视化报告)
├── summary_report.xml(测试任务数据报告)
├── summary.ini(记录测试类型,使用的设备,开始时间和结束时间等信息)
├── task_info.record(记录执行命令,失败用例等清单信息)API使用说明
Hypium测试框架提供了两大类API来支持用例的编写:设备相关API和设备无关API。
设备相关的API主要包括四个基础API类:UiDriver,BY,IUiComponent,UiWindow。
- UiDriver类为UI测试的入口,代表了一个被测设备,提供控件查找、控件检查、用户操作模拟、执行shell命令、安装卸载应用等UI测试核心能力。
- BY对象用于描述需要操作的控件属性,实现控件定位。
- IUiComponent为UiDriver查找返回的控件对象,提供控件属性查询、控件点击、滑动查找等触控/检视能力。
- UiWindow为UiDriver查找返回的窗口对象,提供窗口属性查询、窗口拖动、大小调整等触控能力。
示例代码
# -*- coding: utf-8 -*-
from devicetest.core.test_case import TestCase, Step, CheckPoint
from hypium import *
from hypium.model import WindowFilter
class DemoCase(TestCase):
def __init__(self, configs):
self.TAG = self.__class__.__name__
TestCase.__init__(self, self.TAG, configs)
def setup(self):
pass
def process(self):
# 创建driver对象(self.device1对象在测试用例类中提供)
driver = UiDriver(self.device1)
# 查找控件
component = driver.find_component(BY.text("蓝牙"))
# 查找窗口
window = driver.find_window(WindowFilter().bundle_name("com.huawei.hmos.settings"))
def teardown(self):
pass设备无关的API当前主要包括两个基础API类: host 和CV。
- host 提供基础值断言,PC端shell命令执行等PC端基础操作能力。
- CV 提供图像查找,图像比较,压缩,清晰度计算等基础图像操作能力。
示例代码
from hypium import host, CV
# 执行PC端命令
echo = host.shell("a.bat")
# 调用图像接口
brightness = CV.calculate_brightness("/path/to/image.jpeg")此外Hypium还包含一些常量类型,例如KeyCode,UiParam,MatchPattern等,以及数据类型Point,Rect等。
示例代码
from hypium.model import KeyCode, UiParam, MatchPattern
# 按下电源键(使用常量KeyCode.POWER)
driver.press_key(KeyCode.POWER)
# 向左滑动屏幕(使用常量UiParam.LEFT)
driver.swipe(UiParam.LEFT)下文各小节将详细介绍主要测试场景中Hypium的API的使用方法。
API使用方法
1. 控件查看
通过 DevEco Testing Hypium插件中的 UiViewer 工具,可以查看界面控件的各项属性,有助于在后续测试用例开发中准确定位控件。具体使用方法请参考本文档的“安装向导 -> DevEco Testing Hypium插件安装及使用方法“小节。
2. 控件查找
Hypium 支持三种主要的控件定位方式:控件属性定位、图片匹配定位和比例坐标定位。
从定位的稳定性与可靠性来看,优先级如下:
- 首选:控件属性定位(基于控件的属性信息精确定位);
- 次选:图片匹配定位(适用于属性不可用但界面稳定的场景);
- 备用:比例坐标定位(仅在前两种方式不可用时使用,受分辨率影响较大)。
控件属性定位通过BY选择器对象来实现。下文将详细介绍基于控件属性、图片匹配和比例坐标三种方式的控件定位方法。
单属性定位控件
从hypium包中导入BY选择器对象,从hypium.model包中导入匹配模式常量类MatchPattern。
from hypium import BY
from hypium.model import MatchPattern通过BY对象描述需要查找或者操作的控件对象的属性,例如查找text属性为“蓝牙”的控件。
# 查找text属性为"控件文本"的控件。
component = driver.find_component(BY.text("蓝牙"))
# 读取控件的的边框位置。
bounds = component.getBounds()
# 直接点击控件。
component = driver.touch(BY.text("蓝牙"))注意
默认情况下,find_component和touch等方法会查找/操作第一个条件匹配的控件,如需操作第n个满足匹配条件的控件,请参考查找所有匹配控件。
当前字符串类型的控件属性支持以下五种模糊匹配方式,通过BY选择器方法的第二个可选参数指定,如下表所示:
点击图片可查看完整电子表格
#*点击text属性值前缀为“今天星期”的控件*。
driver.touch(BY.text("今天星期", MatchPattern.STARTS_WITH))BY选择器支持的所有属性如下表所示:
点击图片可查看完整电子表格
多属性组合定位控件
BY选择器支持链式调用,允许用户指定多个控件属性进行联合定位。当界面上存在多个控件的部分属性相同而其他属性不同时,可通过组合条件精确匹配目标控件。
*#点击文本为"蓝牙", 类型为"Button", 并且key为"bluetooth_switch"的按钮*。
driver.touch(BY.text("蓝牙").type("Button").key("bluetooth_switch"))
*# 查找文本为"蓝牙", 类型为"Button", 并且key为"bluetooth_switch"的按钮*。
component = driver.find_component(BY.text("蓝牙").type("Button").key("bluetooth_switch"))控件相对位置+属性组合定位控件
对于某些自身属性不唯一,无法精确定位的控件,BY选择器支持通过与其他控件的相对位置关系来定位控件。支持的相对定位方式如下表所示:
点击图片可查看完整电子表格
注意: 相对位置中的“前后”关系,对应控件树的前序遍历顺序(即深度优先遍历中根-子节点的访问次序),用户可以在 UiViewer 的可视化控件树中直观查看该顺序:控件在列表中从上到下的排列顺序,即为其在相对定位中的从前到后顺序。
相对位置通常和控件的属性结合使用来定位控件。
以下图场景为例,界面上存在多个按钮,用户需要点击显示通知图标之后的按钮,定位方式如下:
- 首先选择一个可以通过属性唯一定位的锚点控件。例如BY.text("显示通知图标")
- 然后找到需要操作的目标控件,选择该控件的一个不唯一属性,通常为type属性。例如BY.type("Button")
- 使用相对位置接口来描述锚点控件和目标控件的位置关系,得到完整的控件选择器。例如BY.type("Button").isAfter(BY.text("显示通知图标")),注意到这里组合使用了type属性和isAfter相对位置接口。
示例代码
# 查找在text属性为"显示通知图标"的控件之后的type属性为"Button"的控件。
component = driver.find_component(BY.type("Button").isAfter(BY.text("显示通知图标")))
# 查找在text属性为"账号"的控件之前的type属性为"Image"的控件。
component = driver.find_component(BY.type("Image").isBefore(BY.text("账号")))
# 查找在key为 "nav_container"内部的类型为"Image"的控件。
component = driver.find_component(BY.type("Image").within(BY.key("nav_container")))
# 查找包名为"com.huawei.hmos.settings"的应用内部的text属性为"蓝牙"的控件。
component = driver.find_component(BY.text("蓝牙").inWindow("com.huawei.hmos.settings"))注意
相对位置中的锚点控件不能再使用相对位置描述,即BY.isBefore方法的参数中不能再出现BY.isBefore或者BY.isAfter等相对定位的方式。
XPath方式查找匹配的控件
BY.xpath匹配器支持通过XPath语法来查找控件。部分控件没有唯一定位的属性,同时通过相对定位的方式也无法准确定位,推荐使用XPath语法来进行更精确的控件定位。
注意
XPath不能和其他属性匹配一起使用,通过XPath查找控件相比 单属性 和多属性查找控件的效率会有所下降。
多属性 > 单属性 > Xpath
在如下场景中,用户需要找到红框标识的图标,然而该图标没有唯一定位的属性,推荐使用XPath语法描述该控件相对其他可定位控件的路径关系来定位该控件。
该页面上,“可用 WLAN”是一个固定的可唯一定位的文本,用户可以首先通过XPath定位到该文本//*[@text='可用 WLAN'],然后定位到该文本控件所在的List控件/ancestor
示例代码
*#查找上图中红框所示的图标,并点击*。
comp = driver.find_component(BY.xpath("//*[@text='可用 WLAN']/ancestor::List/ListItemGroup/ListItem[1]//Text/following::Image"))
comp.click()在支持传入BY选择器的接口均可以使用XPath来定位控件。
# 查找text属性为WLAN的控件。
driver.find_component(BY.xpath("//*[@text='WLAN']"))
driver.find_all_components(BY.xpath("//*[@text='WLAN']"))
driver.wait_for_component(BY.xpath("//*[@text='WLAN']"))
# 点击text属性为WLAN的控件。
driver.touch(BY.xpath("//*[@text='WLAN']"))查找所有匹配控件
默认情况下,driver.find_component接口和其他支持传入BY选择器的接口会查找第一个匹配的控件进行操作。对于需要操作特定次序的匹配控件或所有匹配控件的场景,用户可以使用driver.find_all_components接口。
以如下场景为例,界面上存在多个Button,用户需要点击第2个特定的Button或点击所有Button时,可以使用driver.find_all_components。
示例代码
# 查找所有type属性为"Button"的控件, 如果有匹配的结果,components为列表,包含多个满足条件的IUiComponent对象。
components = driver.find_all_components(BY.type("Button"))
# 点击所有的控件。
for component in components:
driver.touch(component)
# 点击第2个控件。
driver.touch(component[1])图片定位控件
如果控件没有可用于定位的唯一属性,通过相对位置也无法实现定位,可以通过截取控件的图片,使用driver.find_image查找控件的位置,或使用driver.touch_image直接点击控件。
以如下场景为例,若红框中的控件没有可以唯一定位的属性,也无法通过与附近控件的相对位置定位,用户可以尝试使用图片匹配的方式定位控件,定位方式如下:
- 截取红框中图片保存到为template.jpeg(文件名根据需要定义)。
- 调用driver.touch_image,传入template.jpeg图片的路径。
注意
使用图片定位控件需要安装opencv-python包,使用如下命令安装:
python -m pip install opencv-python
示例代码
# 点击屏幕上和模板图片template.jpeg匹配的位置。
driver.touch_image("/path/to/template.jpeg")
# 查找屏幕上和模板图片template.jpeg匹配的位置, bounds为Rect类型,记录了控件上下左右边框的位置。
bounds = driver.find_image("template.jpeg")
print(bounds.top, bounds.left, bounds.bottom, bounds.right)注意
当前仅支持查找匹配度最高的匹配的图片区域,不支持匹配多个目标。
比例坐标定位控件
如果图像特征不明显,使用图像匹配的方式也无法准确识别控件位置,用户可以通过比例坐标的方式点击控件。使用坐标的方式操作控件存在以下两个问题:
- 在屏幕比例或者控件位置发生变化时该方法可能无法操作到预期的控件。
- 当实际操作界面非预期页面时,点击也会成功,但实际执行效果不符合预期。
因此,在使用该方法时,建议用户在前一步或者后一步操作中通过控件属性定位控件,避免脚本未按照预期方式操作设备,但用例仍然可以执行通过的问题。
以下图场景为例,如果红框中的控件无法通过上述方式定位,用户可以采用比例坐标的方式点击。
用户可以通过 UiViewer 工具的控件查看模式获取控件的比例坐标。
# 点击屏幕上(0.52 * 屏幕宽度, 0.98 * 屏幕高度)的位置。
driver.touch((0.52, 0.98))3. 窗口查找
查找窗口
def find_window(filter: WindowFilter) -> UiWindow接口说明
根据指定条件查找窗口,返回窗口对象。
参数说明
点击图片可查看完整电子表格
返回值
如果找到window则返回UiWindow对象,否则返回None。
使用示例
# 查找标题为日历的窗口。
window = driver.find_window(WindowFilter().title("日历"))
# 查找包名为com.huawei.hmos.calendar,并且处于活动状态的窗口。
window = driver.find_window(WindowFilter().bundle_name("com.huawei.hmos.calendar").actived(True))
# 查找处于活动状态的窗口。
window = driver.find_window(WindowFilter().actived(True))
# 查找聚焦状态的窗口。
window = driver.find_window(WindowFilter().focused(True))4. 界面操作
Ⅰ.触摸屏类型
点击
**def touch**(target: **Union**[ISelector, IUiComponent, tuple], mode: str = UiParam.NORMAL, scroll_target: **Union**[ISelector, IUiComponent] = None, wait_time: float = 0.1)接口说明
根据选定的控件或坐标位置执行点击操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 点击文本为"hello"的控件。
driver.touch(BY.text("hello"))
# 点击(100, 200)的位置。
driver.touch((100, 200))
# 点击比例坐标为(0.8, 0.9)的位置。
driver.touch((0.8, 0.9))
# 双击确认按钮(控件文本为"确认", 类型为"Button")。
driver.touch(BY.text("确认").type("Button"), mode=UiParam.DOUBLE)
# 在类型为Scroll的控件上滑动查找文本为"退出"的控件并点击。
driver.touch(BY.text("退出"), scroll_target=BY.type("Scroll"))
# 长按比例坐标为(0.8, 0.9)的位置。
driver.touch((0.8, 0.9), mode="long")长按
def long_click(self, target: Union[ISelector, IUiComponent, tuple], press_time: float = 2, offset=None):接口说明
执行长按操作。
注意:该接口仅DevEco Testing Hypium 6.0.5.200以及更新的版本支持。
参数说明
点击图片可查看完整电子表格
使用示例
*# 长按文本为"按钮"的控件5秒*
driver.long_click(BY.text("按钮"), press_time=5)
*# 长按(100, 200)的位置5秒*
driver.long_click((100, 200), press_time=5)
*# 长按文本为"设置"的控件左上角(偏移0, 0)*
driver.long_click(BY.text("设置"), offset=(0, 0))多指点击
def **multi_finger_touch**(points: **List**[tuple], duration: float = 0.1, area: Rect = None)接口说明
执行多指点击操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 执行多指点击操作, 同时点击屏幕(0.1, 0.2), (0.3, 0.4)的位置。
driver.multi_finger_touch([(0.1, 0.2), (0.3, 0.4)])
# 执行多指点击操作, 设置点击按下时间为1秒。
driver.multi_finger_touch([(0.1, 0.2), (0.3, 0.4)], duration=2)
# 查找Image类型控件。
comp = driver.find_component(BY.type("Image"))
# 在指定的控件区域内执行多指点击(点击坐标为控件区域内的比例坐标)。
driver.multi_finger_touch([(0.5, 0.5), (0.6, 0.6)], area=comp.getBounds())滑动
执行指定方向的滑动操作
**def swipe**(direction: str, distance: int = 60, area: **Union**[ISelector, IUiComponent] = None, side: str = None, start_point: tuple = None, swipe_time: float = 0.3)接口说明
在屏幕上或者指定区域中执行朝向指定方向的滑动操作。该接口用于无需指定精确起始和结束坐标的滑动操作场景。
参数说明
点击图片可查看完整电子表格
使用示例
# 在屏幕上向上滑动, 距离40。
driver.swipe(UiParam.UP, distance=40)
# 在屏幕上向右滑动, 滑动时间为0.1秒。
driver.swipe(UiParam.RIGHT, swipe_time=0.1)
# 在屏幕起始点为比例坐标为(0.8, 0.8)的位置向上滑动,距离30。
driver.swipe(UiParam.UP, 30, start_point=(0.8, 0.8))
# 在屏幕左边区域向下滑动, 距离30。
driver.swipe(UiParam.DOWN, 30, side=UiParam.LEFT)
# 在屏幕右侧区域向上滑动,距离30。
driver.swipe(UiParam.UP, side=UiParam.RIGHT)
# 在类型为Scroll的控件中向上滑动。
driver.swipe(UiParam.UP, area=BY.type("Scroll"))执行指定起始结束位置的精确滑动操作
**def slide**(start: **Union**[ISelector, tuple], end: **Union**[ISelector, tuple], area: **Union**[ISelector, IUiComponent] = None, slide_time: float = 0.3)接口说明
根据指定的起始和结束位置执行滑动操作,起始和结束的位置可以为控件或屏幕坐标。该接口用于执行精准的滑动操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 从类型为Slider的控件滑动到文本为最大的控件
driver.slide(BY.type("Slider"), BY.text("最大"))
# 从坐标100, 200滑动到300,400
driver.slide((100, 200), (300, 400))
# 从坐标100, 200滑动到300,400, 滑动时间为3秒
driver.slide((100, 200), (300, 400), slide_time=3)
# 在类型为Slider的控件上从(0, 0)滑动到(100, 0)
driver.slide((0, 0), (100, 0), area = BY.type("Slider"))拖拽
**def drag**(start: **Union**[ISelector, tuple, IUiComponent], end: Union[ISelector, tuple, IUiComponent], area: Union[ISelector, IUiComponent] = None, press_time: float = 1, drag_time: float = 1)接口说明
根据指定的起始和结束位置执行拖拽操作,起始和结束的位置可以为控件或者屏幕坐标。
参数说明
点击图片可查看完整电子表格
使用示例
*# 拖拽文本为"文件.txt"的控件到文本为"上传文件"的控件。
driver.drag(BY.text("文件.txt"), BY.text("上传文件"))
# 拖拽id为"start_bar"的控件到坐标(100, 200)的位置, 拖拽时间为2秒。
driver.drag(BY.key("start_bar"), (100, 200), drag_time=2)
# 在id为"Canvas"的控件上执行拖拽操作,从"Canvas"控件中(0.1, 0.5)的位置拖拽到(0.9, 0.5)位置。
# 假如"Canvas"控件左上角坐标(100, 100), 宽度为200,高度为50,此操作等价于
# driver.drag((100 + 0.1 * 200, 100 + 0.5 * 50), (100 + 0.9 * 200, 100 + 0.5 * 50))。
driver.drag((0.1, 0.5), (0.9, 0.5), area=BY.id("Canvas"))
# 在滑动条上执行拖拽操作, 以滑动条组件左上角为原点, 从滑动条区域中的(10, 10)拖拽到(10, 200)。
# 假设滑动条左上角坐标为(500, 500), 此操作等价于driver.drag((500 + 10, 500 + 10), (500 + 10, 500 + 200))。
driver.drag((10, 10), (10, 200), area=BY.type("Slider"))*捏合缩小
**def pinch_in**(area: **Union**[ISelector, IUiComponent, Rect], scale: float = 0.4, direction: str = "diagonal", **kwargs)接口说明
在指定控件上执行双指捏合缩小操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 在类型为Image的控件上进行双指捏合缩小操作。
driver.pinch_in(BY.type("Image"))
# 在类型为Image的控件上进行双指捏合缩小操作, 设置水平方向捏合。
driver.pinch_in(BY.type("Image"), direction="horizontal")双指放大
**def pinch_out**(area: **Union**[ISelector, IUiComponent, Rect], scale: float = 1.6, direction: str = "diagonal", **kwargs)接口说明
在指定控件上执行双指放大操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 在类型为Image的控件上进行双指放大操作。
driver.pinch_out(BY.type("Image"))
# 在类型为Image的控件上进行双指捏合缩小操作, 设置水平方向捏合。
driver.pinch_out(BY.type("Image"), direction="horizontal")双指滑动
def two_finger_swipe(start1: tuple, end1: tuple, start2: tuple, end2: tuple, duration: float = 0.5, area: Rect = None)接口说明
执行双指滑动操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 执行双指滑动操作, 手指1从(0.4, 0.4)滑动到(0.2, 0.2), 手指2从(0.6, 0.6)滑动到(0.8, 0.8)。
driver.two_finger_swipe((0.4, 0.4), (0.2, 0.2), (0.6, 0.6), (0.8, 0.8))
# 执行双指滑动操作, 手指1从(0.4, 0.4)滑动到(0.2, 0.2), 手指2从(0.6, 0.6)滑动到(0.8, 0.8), 持续时间3秒。
driver.two_finger_swipe((0.4, 0.4), (0.2, 0.2), (0.6, 0.6), (0.8, 0.8), duration=3)
# 查找Image类型控件。
comp = driver.find_component(BY.type("Image"))
# 在指定的控件区域内执行双指滑动(滑动起始/停止坐标为控件区域内的比例坐标)。
driver.two_finger_swipe((0.4, 0.4), (0.1, 0.1), (0.6, 0.6), (0.9, 0.9), area=comp.getBounds())自定路径滑动手势(单指)
**def inject_gesture**(gesture: Gesture, speed: int = 2000)接口说明
执行自定义滑动手势操作。
参数说明
点击图片可查看完整电子表格
使用示例
from hypium.uidriver import Gesture
# 创建一个gesture对象。
gesture = Gesture()
# 获取控件计算器的位置。
pos = driver.findComponent(BY.text("计算器")).getBoundsCenter()
# 获取屏幕尺寸。
size = driver.getDisplaySize()
# 起始位置, 长按2秒。
gesture.start(pos.to_tuple(), 2)
# 移动到屏幕边缘。
gesture.move_to(Point(size.X - 20, int(size.Y / 2)).to_tuple())
# 停留2秒。
gesture.pause(2)
# 移动到(360, 500)的位置。
gesture.move_to(Point(360, 500).to_tuple())
# 停留2秒结束。
gesture.pause(2)
# 执行gesture对象描述的操作。
driver.inject_gesture(gesture)自定路径滑动手势(多指)
def inject_multi_finger_gesture(gestures: List[Gesture], speed: int = 6000)接口说明
注入多指手势操作。
参数说明
点击图片可查看完整电子表格
使用示例
from hypium.uidriver import Gesture
# 创建手指1的手势, 从(0.4, 0.4)的位置移动到(0.2, 0.2)的位置。
gesture1 = Gesture().start((0.4, 0.4)).move_to((0.2, 0.2), interval=1)
# 创建手指2的手势, 从(0.6, 0.6)的位置移动到(0.8, 0.8)的位置。
gesture2 = Gesture().start((0.6, 0.6)).move_to((0.8, 0.8), interval=1)
# 注入多指操作。
driver.inject_multi_finger_gesture((gesture1, gesture2))Ⅱ. 键盘鼠标
鼠标点击
**def mouse_click**(pos: **Union**[tuple, IUiComponent, ISelector], button_id: MouseButton = MouseButton.MOUSE_BUTTON_LEFT, key1: Union[KeyCode, int] = None, key2: **Union**[KeyCode, int] = None)接口说明
执行鼠标点击操作, 支持键鼠组合操作。
参数说明
点击图片可查看完整电子表格
使用示例
# 使用鼠标左键点击(100, 200)的位置。
driver.mouse_click((100, 200), MouseButton.MOUSE_BUTTON_LEFT)
# 使用鼠标右键点击文本为"确认"的控件。
driver.mouse_click(BY.text("确认"), MouseButton.MOUSE_BUTTON_RIGHT)
# 使用鼠标右键点击比例坐标(0.8, 0.5)的位置。
driver.mouse_click((0.8, 0.5), MouseButton.MOUSE_BUTTON_RIGHT)鼠标拖拽
**def mouse_drag**(start: **Union**[tuple, IUiComponent, ISelector], end: **Union**[tuple, IUiComponent, ISelector], speed: int = 3000)接口说明
执行鼠标拖拽操作(即按住鼠标左键并移动鼠标)。
参数说明
点击图片可查看完整电子表格
使用示例
# 鼠标从控件1拖拽到控件2。
driver.mouse_drag(BY.text("控件1"), BY.text("控件2"))鼠标移动
**def mouse_move**(start: **Union**[tuple, IUiComponent, ISelector], end: **Union**[tuple, IUiComponent, ISelector], speed: int = 3000)接口说明
将鼠标指针从指定起始位置移动到结束位置,模拟移动轨迹和移动速度。
参数说明
点击图片可查看完整电子表格
使用示例
# 鼠标从控件1移动到控件2。
driver.mouse_move(BY.text("控件1"), BY.text("控件2"))按键
def press_key(key_code: Union[KeyCode, int], key_code2: Union[KeyCode, int] = None, mode="normal")接口说明
执行按键操作(注意不推荐使用该接口实现组合按键模拟,模拟组合按键键请使用press_combination_key)。
参数说明
点击图片可查看完整电子表格
使用示例
# 按下电源键。
driver.press_key(KeyCode.POWER)
# 长按电源键。
driver.press_key(KeyCode.POWER, mode=UiParam.LONG)
# 按下音量下键。
driver.press_key(KeyCode.VOLUME_DOWN)按组合键
**def press_combination_key**(key1: **Union**[KeyCode, int], key2: **Union**[KeyCode, int], key3: **Union**[KeyCode, int] = None)接口说明
执行组合键操作,支持2键或3键组合。
参数说明
点击图片可查看完整电子表格
使用示例
# 按下音量下键和电源键的组合键
driver.press_combination_key(KeyCode.VOLUME_DOWN, KeyCode.POWER)
# 同时按下ctrl, shift和F键
driver.press_combination_key(KeyCode.CTRL_LEFT, KeyCode.SHIFT_LEFT, KeyCode.F)5. hdc/shell命令执行
hdc命令执行
**def hdc**(cmd, timeout: float = 60) -> str接口说明
执行hdc命令。
参数说明
点击图片可查看完整电子表格
返回值
命令执行后的回显内容。
使用示例
# 执行hdc命令list targets。
echo = driver.hdc("list targets")
# 执行hdc命令hilog, 设置30秒超时。
echo = driver.hdc("hilog", timeout = 30)设备侧shell命令执行
**def shell**(cmd: str, timeout: float = 60) -> str接口说明
在设备端shell中执行命令。
参数说明
点击图片可查看完整电子表格
返回值
命令执行后的回显内容。
使用示例
# 在设备shell中执行命令ls -l。
echo = driver.shell("ls -l")
# 在设备shell中执行命令top, 设置10秒超时时间。
echo = driver.shell("top", timeout=10)PC侧shell命令执行
**def shell**(cmd: **Union**[str, list], timeout: float = 300) -> str接口说明
在PC端执行shell命令。
参数说明
点击图片可查看完整电子表格
使用示例
# 在PC端执行dir命令。
echo = host.shell("dir")
# 在PC端执行netstat命令读取回显结果, 设置超时时间为10秒。
echo = host.shell("netstat", timeout=10)应用预置操作
安装应用
**def install_app**(package_path: str, options: str = "", **kwargs)接口说明
安装指定应用安装包。
参数说明
点击图片可查看完整电子表格
使用示例
# 安装路径为test.hap的安装包到手机。
driver.install_app(r"test.hap")
# 替换安装路径为test.hap的安装包到手机(增加-r参数指定替换安装)。
driver.install_app(r"test.hap", "-r")卸载应用
**def uninstall_app**(package_name: str, **kwargs)接口说明
卸载指定包名应用。
参数说明
点击图片可查看完整电子表格
使用示例
# 卸载包名为com.test.myapp的应用。
driver.uninstall_app("com.test.myapp")清除应用缓存数据
**def clear_app_data**(package_name: str)接口说明
清除应用的缓存数据。
参数说明
点击图片可查看完整电子表格
使用示例
# 清除包名为com.test.myapp的应用的缓存数据。
driver.clear_app_data("com.test.myapp")启动应用
def **start_app**(package_name: str, page_name: str = None, params: str = "", wait_time: float = 1)接口说明
根据包名启动指定的应用。
参数说明
点击图片可查看完整电子表格
使用示例
# 启动浏览器。
driver.start_app("com.huawei.hmos.browser", "MainAbility")停止应用
**def stop_app**(package_name: str, wait_time: float = 0.5)接口说明
停止指定包名的应用。
参数说明
点击图片可查看完整电子表格
使用示例
# 停止包名为com.huawei.hmos.settings的应用。
driver.stop_app("com.huawei.hmos.settings")6. 文件拉取/推送
拉取文件
**def pull_file**(device_path: str, local_path: str = None, timeout: int = 60)接口说明
从设备端的传输文件到PC端。
参数说明
点击图片可查看完整电子表格
使用示例
# 从设备中拉取文件"/data/local/tmp/test.log"保存到PC端的test.log。
driver.pull_file("/data/local/tmp/test.log", "test.log")推送文件
**def push_file**(local_path: str, device_path: str, timeout: int = 60)接口说明
从PC端传输文件到设备端。
参数说明
点击图片可查看完整电子表格
使用示例
# 从PC端推送文件test.hap保存到设备端的"/data/local/tmp/test.hap"。
driver.push_file("test.hap", "/data/local/tmp/test.hap")查询文件是否存在
**def has_file**(file_path: str) -> bool接口说明
查询设备中是否有存在路径为file_path的文件。
参数说明
点击图片可查看完整电子表格
使用示例
# 查询设备端是否存在文件/data/local/tmp/test_file.txt。
driver.has_file("/data/local/tmp/test_file.txt")7. 文本输入/清除
输入文本
def input_text(component: Union[ISelector, IUiComponent, tuple], text: str, mode: InputTextMode = None):接口说明
向指定控件中输入文本内容。
参数说明
点击图片可查看完整电子表格
使用示例
from hypium import BY
from hypium.model import InputTextMode
# 在类型为"TextInput"的控件中输入文本"hello world"。
driver.input_text(BY.type("TextInput"), "hello world")
# 在类型为"TextInput"的控件中使用剪切板一次性输入文本"hello world"。
driver.input_text(BY.type("TextInput"), "hello world", mode=InputTextMode().paste(True))
# 在类型为"TextInput"的控件中使用剪切板一次性并追加输入文本"hello world"。
driver.input_text(BY.type("TextInput"), "hello world", mode=InputTextMode().paste(True).addition(True))清除文本
**def clear_text**(component: [ISelector, IUiComponent])接口说明
清空指定控件中的文本内容。
参数说明
点击图片可查看完整电子表格
使用示例
# 清除类型为"InputText"的控件中的内容。
driver.clear_text(BY.type("InputText"))8. 断言
Ⅰ. 常规断言
检查是否相等
**def check_equal**(value: **Any**, expect: **Any** = True, fail_msg: str = None, expect_equal=True)接口说明
检查实际值和期望值相等,在不一致时抛出异常,并打印fail_msg。
参数说明
点击图片可查看完整电子表格
使用示例
*#检查a等于b*。
host.check_equal(a, b, "a != b")检查是否超过预期值
**def check_greater**(value: **Any**, expect: **Any**, fail_msg: str = None)接口说明
检查value是否大于expect,不满足时抛出异常,并在日志中打印fail_msg。
参数说明
点击图片可查看完整电子表格
使用示例
*检查a大于b*
host.check_greater(a, b)Ⅱ. 控件断言
检查控件是否存在
**def check_component_exist**(component: ISelector, expect_exist: bool = True, wait_time: int = 0, scroll_target: **Union**[ISelector, IUiComponent] = None)接口说明
检查指定控件在当前界面是否存在。
参数说明
点击图片可查看完整电子表格
使用示例
# 检查类型为Button的控件存在。
driver.check_component_exist(BY.type("Button"))
# 检查类型为Button的控件存在,如果不存在等待最多5秒。
driver.check_component_exist(BY.type("Button"), wait_time=5)
# 在类型为Scroll的控件上滚动检查文本为"hello"的控件存在。
driver.check_component_exist(BY.text("hello"), scroll_target=BY.type("Scroll"))
# 检查文本为确认的控件不存在。
driver.check_component_exist(BY.text("确认"), expect_exist=False)检查控件属性
**def check_component**(component: **Union**[ISelector, IUiComponent], expected_equal: bool = True, **kwargs)接口说明
检查当前界面上指定控件的属性是否符合预期。
参数说明
点击图片可查看完整电子表格
使用示例
# 检查id为xxx的控件的checked属性为True。
driver.check_component(BY.key("xxx"), checked=True)
# 检查id为check_button的按钮enabled属性为True。
driver.check_component(BY.key("checked_button"), enabled=True)
# 检查id为container的控件文本内容为“正在检查”。
driver.check_component(BY.key("container"), text="正在检查")
# 检查id为container的控件文本内容不为空。
driver.check_component(BY.key("container"), text="", expect_equal=False)检查图片是否存在
def check_image_exist(image_path_pc: str, expect_exist: bool = True, similarity: float = 0.95, timeout: int = 3, mode="template", **kwargs)接口说明
使用图片模板匹配算法检测当前屏幕截图中是否有指定图片,需要保证模板图片的分辨率和屏幕截图中目标图像的分辨率一致。
参数说明
点击图片可查看完整电子表格
使用示例
# 检查图片存在。
driver.check_image_exist("test.jpeg")
# 检查图片不存在。
driver.check_image_exist("test.jpeg", expect_exist=False)
# 检查图片存在, 图片相似度要求95%, 重复检查时间5秒。
driver.check_image_exist("test.jpeg", timeout=5, similarity=0.95)
# 检查图片不存在, 重复检查时间5秒。
driver.check_image_exist("test.jpeg", timeout=5, expect_exist=False)
# 使用sift算法检查图片存在, 设置最少匹配特征点数量为16。
driver.check_image_exist("test.jpeg", mode="sift", min_match_point=16)Ⅲ. 窗口断言
检查窗口
**def check_window**(window: WindowFilter, title: str = None, bundle_name: str = None)接口说明
检查指定的window的属性是否符合预期。
参数说明
点击图片可查看完整电子表格
使用示例
*#检查当前焦点窗口的包名为com.huawei.hmos.settings*。
driver.check_window(WindowFilter().focused(True), bundle_name="com.huawei.hmos.settings")9. 日志打印
用户使用以下方法可以在测试用例脚本中打印日志,日志会记录到测试报告中。
from devicetest.core.test_case import Step, CheckPoint, MESSAGE
Step("点击按钮")
CheckPoint("检查联系人存在")
MESSAGE("打印一条提示消息")在自定义实现的接口中,可以调用driver对象中的log模块打印日志消息,对应日志也会记录到测试报告中。
driver.log.debug("debug级别的日志")
driver.log.info("info级别的日志")
driver.log.warning("warning级别的日志")
driver.log.error("error级别的日志")- 读取测试项目中资源文件路径
用户可通过以下接口读取测试工程资源目录中的文件路径。接口接收文件名或相对路径作为参数,搜索测试工程资源文件目录并返回文件的完整路径。若未找到对应文件,则抛出异常。
from devicetest.utils import file_util
file_path = file_util.get_resource_path("filename")该接口默认搜索文件,开发者可以设置isdir=True来搜索目录路径。
dir_path = file_util.get_resource_path("dirname", isdir=True)调试Debug技巧
当前单个脚本 可以点击 插件图标,选择快速 调试此段函数

插件框架 会自动生成一个
# -*- coding: utf-8 -*-
import sys
sys.path.append(r"E:\code\python\GAC_Hypium")
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
from hypium import *
if __name__ == '__main__':
connector_server = ("127.0.0.1", 8710)
config = {"connector_server": ["127.0.0.1", "8710"]}
driver = UiDriver.connect(connector="hdc", log_level="debug", device_sn="2MH0224521018321", config=config, connector_server=connector_server)
from hypium import *
from devicetest.core.test_case import TestCase, Step, CheckPoint
driver.touch(BY.text("我的").type("Text"))
driver.wait(0.5)
driver.touch(BY.isAfter(BY.type('Image')).isBefore(BY.type('Refresh')).type('Image'))
driver.wait(0.5)
driver.touch(BY.isAfter(BY.text('个性化推荐')).isBefore(BY.text('调试')).type('Row'))
driver.wait(0.5)
driver.touch(BY.isAfter(BY.type('Image')).isBefore(BY.text('当前环境:')).type('Column'))
driver.wait(0.5)
driver.touch(BY.type('uat'))
driver.wait(0.5)
exist = driver.check_component_exist(BY.text("uat"))
if exist:
component_uat = driver.find_component(BY.text("uat"))
component_uat.click()
driver.stop_app(package_name="com.cloudy.component.hos", wait_time=3)
else:
print("查找uat 环境失败")常见问题
Xpath 定位不能同时使用其他 选择器
(<class 'ValueError'>, ValueError("xpath can't used with other attribute selector"), <traceback object at 0x0000019147D6D240>)10. Xpath 定位失败
(<class 'devicetest.core.exception.DeviceTestError'>, DeviceTestError("Can't find component with [/root/Column/Tabs/TabBar/Column[5]/Column/Text]"), <traceback object at 0x00000169C843AB80>)11. 测试套 配置文件Json 配置错误
11.1 testsuite 路径 一定要写对!
若使用相对路径,需相对于 测试工程根目录 = testcases 文件夹;
#自定义设置 =测试工程根目录 testcases 文件夹 / Ts_002文件夹 /Ts_002 当前JSON文件 同名的 Ts_002.py
"testsuite": "Ts_002/Ts_002",- 若未指定,则默认查找与当前 JSON 文件同目录下同名的 Python文件

11.2 suitecases字段 要填对
- // 方式一:定义 suitecases 字段,并在其中指定测试用例脚本文件的路径。路径可使用相对路径或绝对路径;若使用相对路径,其根目录为当前测试套目录。
[2026-05-09 15:35:42,725] [26444] [DeviceTest] [ERROR] [[Script-0203012] No test list found] [ErrorNo=00000]
[2026-05-09 15:35:42,726] [26444] [DeviceTest] [ERROR] [[Script-0203012] No test list found]
Traceback (most recent call last):
File "F:\anaconda3\envs\py312\Lib\site-packages\devicetest\driver\device_test.py", line 126, in do_driver_execute
test_list = driver_obj._get_test_list(json_config, request, source)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\anaconda3\envs\py312\Lib\site-packages\devicetest\driver\device_test.py", line 400, in _get_test_list
raise ParamError(err_msg)
_core.exception.ParamError: [Script-0203012] No test list found[2026-05-09 15:38:58,707] [30056] [DeviceTest] [ERROR] [[Environment-0101002] File path does not exist, path: Ts_002.pyc]
[2026-05-09 15:38:58,707] [30056] [DeviceTest] [ERROR] [[Script-0203012] No test list found] [ErrorNo=00000]
[2026-05-09 15:38:58,707] [30056] [DeviceTest] [ERROR] [[Script-0203012] No test list found]
Traceback (most recent call last):
File "F:\anaconda3\envs\py312\Lib\site-packages\devicetest\driver\device_test.py", line 126, in do_driver_execute
test_list = driver_obj._get_test_list(json_config, request, source)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\anaconda3\envs\py312\Lib\site-packages\devicetest\driver\device_test.py", line 400, in _get_test_list
raise ParamError(err_msg)
_core.exception.ParamError: [Script-0203012] No test list found