Appium: Windows系统桌面应用自动化测试(三) 【脚本操作】

news2024/11/17 23:20:32

Appium: Windows系统桌面应用自动化测试 【脚本操作】

  • 一、常用操作
    • 1、添加被测程序
      • 1.1示例一:通过程序路径指定应用程序,例如指定写字板程序路径。
      • 1.2示例二:通过程序ID指定应用程序,例如指定计算器ID。
      • 1.3 应用程序ID(AppId)
    • 2、启动参数
    • 3、元素定位
    • 4、窗口操作
    • 5、Root窗口
      • 5.1、根据示例描述编写如下代码:
    • 6、切换新窗口
      • 6.1、实现代码如下:
    • 7、文件操作
    • 8、切换输入法
  • 二、脚本实战

一、常用操作

WinApp自动化测试脚本是使用Appium客户端完成开发的,一些基本的操作方法可参考Appium的API。本节主要介绍WinApp在脚本编写时与移动端App脚本开发上不同的地方。

1、添加被测程序

设置启动程序是在启动参数中添加key为app的参数,值可以是应用程序的ID,也可以是应用程序的完整路径。

1.1示例一:通过程序路径指定应用程序,例如指定写字板程序路径。

desired_caps = {}
desired_caps['app'] = r"C:\Program Files\Windows NT\Accessories\wordpad.exe"

1.2示例二:通过程序ID指定应用程序,例如指定计算器ID。

desired_caps = {}
desired_caps["app"] = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"

1.3 应用程序ID(AppId)

应用程序ID(AppId)是应用程序用户模型 ID (AppUserModelID),简称 AUMID。在Windows PowerShell中输入命令Get-StartApps便可看到当前用户安装的所有应用名称和 AUMID

PS C:\Users\pc> Get-StartApps

Name                                  AppID
----                                  -----
Python 3.9 (64-bit)                   C:\Users\pc\AppData\Local\Programs\Python\Python39\python.exe
Google Chrome                         Chrome.JOYETIBVDRAA6DX32OHIYXNRNI
uc-devtools                           com.squirrel.uc-devtools.uc-devtools
SakuraCat                             com.tidalab.client
微信                                  D:\Program Files (x86)\Tencent\WeChat\WeChat.exe
Internet Explorer                     Microsoft.InternetExplorer.Default
闹钟和时钟                            Microsoft.WindowsAlarms_8wekyb3d8bbwe!App
计算器                                Microsoft.WindowsCalculator_8wekyb3d8bbwe!App

***************************************************
*****************   省略部分内容    *****************
***************************************************
手机连接                              Microsoft.YourPhone_8wekyb3d8bbwe!App
Microsoft Store                       Microsoft.WindowsStore_8wekyb3d8bbwe!App
天气                                  Microsoft.BingWeather_8wekyb3d8bbwe!App
Solitaire Collection                  Microsoft.MicrosoftSolitaireCollection_8wekyb3d8bbwe!App

PS C:\Users\pc>

从上内容可以看到已经安装的所有应用AUMID,例如闹钟和时钟应用的AUMID就是Microsoft.WindowsAlarms_8wekyb3d8bbwe!App。

2、启动参数

WinApp自动化测试中,在创建Windows应用程序驱动会话时,可以使用的启动参数是有限的
在这里插入图片描述在这里插入图片描述
appTopLevelWindow值是窗口句柄,用于设置应用程序顶层窗口,如图
在这里插入图片描述

UIA树中就可以知道打开的写字板程序的顶层窗口为【窗格 ‘文档-写字板’】。appTopLevelWindow值是一个16进制,可以通过许多方法获取,
例如

  • hex(win32gui.FindWindow()
  • hex(int(driver.find_element(By.XX,‘XX’).get_attribute(‘NativeWindowHandle’)))

3、元素定位

WinAppDriver支持许多方式查找元素。如表7-2列出了支持的定位方式及在Accessibility Insights For Windows工具和Inspect.exe工具中显示的对应元素属性。
在这里插入图片描述
在这里插入图片描述//Button[0]

4、窗口操作

我们可以使用Selenium提供的一些API操作WinApp窗口,例如窗口最大化、设置窗口位置、设置窗口大小、关闭窗口等。

一些Selenium提供的API同样适用于WinApp窗口的方法。
在这里插入图片描述
在这里插入图片描述

5、Root窗口

如果在启动参数中app参数的值给定的是一个具体的应用程序ID或完整的路径,那么启动会话后appTopLevelWindow默认就是该应用的根节点。

例如指定的应用程序是写字板,那么启动后会话的appTopLevelWindow默认就是【窗格 ‘文档-写字板’】,后续操作都会将【窗格 ‘文档-写字板’】作为开始节点,例如通过XPATH方式查找元素,就会从该节点开始查找,窗口切换时窗口查找也是查找该节点下的窗口。

但是从图
在这里插入图片描述

UIA树中可以看到,实则还有一个节点【窗格 ‘桌面 1’】,即Root窗口,此节点才是Windows桌面最顶层的窗口,此节点的子节点才是应用程序的根节点。

如果将启动参数app的值设置为‘Root’,那么启动会话后appTopLevelWindow就是Root窗口,表示我们的系统桌面。例如将启动参数app的值设置为‘Root’,然后依次桌面应用程序控制面板和此电脑。

使用Accessibility Insights For Windows工具查看桌面上的元素,如图
在这里插入图片描述

所示。从图中可以知道,控制面板和此电脑都有Name属性,因此可以使用NAME定位方式定位元素。

5.1、根据示例描述编写如下代码:


# window_root.py
import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains


# 添加启动参数
desired_caps = {}
desired_caps['app'] = "Root"
# 客户端连接 Server,启动 Session 会话
driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', desired_capabilities=desired_caps)
time.sleep(3)

control_panel_element = driver.find_element(By.NAME, '控制面板')
# 双击桌面上的控制面板
ActionChains(driver).double_click(control_panel_element).perform()
time.sleep(1)

my_computer_element = driver.find_element(By.NAME, '此电脑')
# 双击桌面上的此电脑
ActionChains(driver).double_click(my_computer_element).perform()
time.sleep(1)

# 关闭会话
driver.quit()

运行脚本后,会观察到鼠标先双击桌面上的控制面板并打开,然后双击桌面上的回收站并打开。

注意:此操作是点击桌面上的应用程序,运行脚本时不能有窗口遮挡控制面板和回收站图标,否则会点击到对应位置最上面的窗口上。另一种解决方法是在点击桌面上的应用程序之前,通过脚本先发送快捷键 Win+d,将桌面完全显示出来。

6、切换新窗口

窗口切换与浏览器中的窗口切换相同,如果想操作新窗口,就需要先切换进新窗口。Appium能识别到的窗口是appTopLevelWindow窗口的子窗口,如果是切换appTopLevelWindow窗口的子窗口,则可以通过window_handles、current_window_handle、switch_to.window(window_name)三个API完成切换。

  • window_handles:获取所有的appTopLevelWindow下的窗口句柄。
  • current_window_handle:获得当前窗口句柄。
  • switch_to.window(window_name):切换窗口,参数window_name为窗口句柄。

提示:WinAppDriver、Appium、Selenium三者之间的兼容性处理并不是很好,所以句柄的获取会存在很多问题,因此直接使用window_handles获取窗口句柄会有些吃力的。但相信在不久的将来,该问题会得到改善。

因此,如果打开了一个新窗口,而新窗口不在当前会话的appTopLevelWindow节点下,我们就需要根据新窗口句柄启动一个新的会话,开启的新会话就将会话绑定到新窗口上。例如打开写字板程序后,点击插入绘图打开画图窗口,然后关闭画图窗口,最后关闭写字板。

6.1、实现代码如下:

# switch_window.py
import time
import win32gui
from appium import webdriver
from selenium.webdriver.common.by import By


# 添加启动参数
desired_caps = {}
desired_caps['app'] = r"C:\Program Files\Windows NT\Accessories\wordpad.exe"
# 客户端连接 Server,启动 Session 会话
driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', desired_capabilities=desired_caps)
time.sleep(1)
driver.set_window_size(1000, 600)

# 打开绘图窗口
driver.find_element(by=By.NAME, value="绘图").click()
time.sleep(1)

# 获取画图窗口句柄
paint_handle = win32gui.FindWindow(None, '位图图像 在 文档 中 - 画图')
# 配置启动参数,并且启动一个新会话
paint_session = webdriver.Remote(command_executor='http://127.0.0.1:4723',
                           desired_capabilities={"appTopLevelWindow": hex(paint_handle)})

# 点击画图窗口中的 关闭 按钮
paint_session.find_element(by=By.NAME, value="关闭").click()
# 关闭会话
paint_session.quit()

# 点击写字板窗口中的 关闭 按钮
driver.close()
time.sleep(1)
driver.find_element(by=By.NAME, value="不保存(N)").click()
# 关闭会话
driver.quit()

7、文件操作

WinApp自动化上使用代码实现文件上传、文件下载、文件保存或文件另存为都是非常简单的,操作也是相同的,因为都是操作Windows系统应用程序上的窗口,我们只需要根据行为进行元素定位,元素操作即可。下面我们以文件上传为例讲解代码的实现。

由于文件上传的操作步骤都是一致的,因此可以将上传文件场景进行封装,然后调用。例如在写字板中上传图片,当打开上传图片窗口后,先定位文件路径输入框元素并且输入文件路径 ,然后点击打开按钮即可将文件上传到写字板中。实现代码如下:

# upload_file.py
import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


def upload_file(driver, file):
    # 定位文件路径输入框并输入文件路径
    file_input = WebDriverWait(driver, 60, 0.5).until(EC.visibility_of_element_located((By.XPATH, "//Edit[@Name='文件名(N):']")))
    file_input.send_keys(file)
    # 定位打开按钮并点击
    file_open_btn = WebDriverWait(driver, 60, 0.5).until(EC.visibility_of_element_located((By.XPATH, "//Button[@Name='打开(O)']")))
    file_open_btn.click()

# 添加启动参数
desired_caps = {}
desired_caps['app'] = r"C:\Program Files\Windows NT\Accessories\wordpad.exe"
# 客户端连接 Server,启动 Session 会话
driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', desired_capabilities=desired_caps)
time.sleep(1)
driver.set_window_size(1000, 600)
time.sleep(1)
# 点击图片,上传文件
(driver.find_elements(by=By.XPATH, value="//Group"))[4].click()

# 文件上传
upload_file(driver, r"D:\ty.png")

# 关闭程序和会话
driver.close()
driver.find_element(by=By.NAME, value="不保存(N)").click()
driver.quit()

注意:运行上面脚本时输入法需要切换到英文,如果是中文输入法,文件路径输入的结果会与预期不一致。

运行上面脚本,可以观察到先启动写字板程序,然后点击了图片图标打开了上传文件窗口,接着文件上传输入框中输入了文件路径,并且点击了打开按钮,此时可以看到写字板中已经成功插入了图片,最后关闭写字板程序,会话关闭。
在这里插入图片描述

8、切换输入法

自动化脚本在输入内容时会受到输入法的影响,例如我们原本想输入内容“D2”,但由于输入法是中文,因此得到的内容将是输入拼音D后列出的第二个汉字,完全与期望相差甚远。

我们在Windows系统上打开一个新程序后,新程序的输入法会是默认语言,例如输入法默认是中文,在Word文件中切换到了英文,当打开记事本后输入法会是默认的中文,当再切回到Word文件时输入法也会跟着切换回英文。

因此我们可以通过设置输入法的默认值达到预期的结果,操作步骤是:Windows10系统下右键点击右下角输入法,然后依次选择【设置】>>【常规】,在默认模式下将【选择输入法默认模式】下拉框选择为预取语言即可,如图标记处,就是将输入法的默认值设置为了英文。

在这里插入图片描述
但是项目自动化中我们还是会遇到需要切换输入法的场景。此时我们可以通过输入法切换的快捷键快速实现。例如笔者的默认输入法是中文,中英文切换的快捷键是Shift,改造上面代码中的文件上传函数,在文件路径输入框输入内容前先发送一个Shift快捷键,使输入法切换到英文,然后再输入文件路径。改造后的文件上传函数如下:

def upload_file(driver, file):
    # 定位文件路径输入框并输入文件路径
    file_input = WebDriverWait(driver, 60, 0.5).until(
        EC.presence_of_element_located((By.XPATH, "//Edit[@Name='文件名(N):']")))
    # 输入框输入 Shift,由中文切换到英文
    file_input.send_keys(Keys.SHIFT)
    file_input.send_keys(file)
    # 定位打开按钮并点击
    file_open_btn = WebDriverWait(driver, 60, 0.5).until(
        EC.presence_of_element_located((By.XPATH, "//Button[@Name='打开(O)']")))
    file_open_btn.click()

提示:Windows10系统下设置输入法切换的快捷键步骤是:右键点击右下角输入法,然后依次选择【设置】>>【按键】,即可在页面模式切换下找到【中/英文模式切换】、【全/半角切换】等快捷键设置项。

二、脚本实战

以操作 PC 端的微信为例,聊聊自动化的常见步骤

  • 首先,我们在本机打开 WinAppDriver 服务,让它在后台运行
    然后,我们使用 Python 编写自动化脚本
    通过 ip 地址、端口号及 PC 版微信的绝对路径,使用 Appium 打开微信
import time, os
from appium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from time import sleep

class Auto():

    def open_weixin(self, host='localhost', port=4723):
        # 打开WinAppDriver服务
        # 注意:如果手动开启,则可以注释掉
        # os.system(r'start "" /d "C:\Program Files\Windows Application Driver\"  "WinAppDriver.exe"')

        # 配置信息
        # 包含:平台名、系统、应用程序绝对路径
        desired_caps = {'platformName': 'Windows', 'deviceName': 'WindowsPC',
                        'app': r"D:\Program Files (x86)\Tencent\WeChat\WeChat.exe"}

        try:
            # 连接WinAppDriver服务,打开目标软件
            self.driver = webdriver.Remote('http://{}:{}'.format(host, port), desired_caps)
        except Exception as e:
            raise AssertionError(e)
  • 接着,通过「 组件元素识别工具 」拿到界面元素的属性值,执行常见的点击、移动、滑动等操作
    比如:点击「 文件传输助手 」,发送一条信息
# 给文件传输助手发送一条信息
def send_msg(self, element_name, msg):
    """
    :param element_name:元素name值
    :param msg:
    :return:
    """
    # 通过name属性,找到目标元素
    chat_element = self.weixin_driver.find_element_by_name(target_name)

    # 点击元素,进入聊天界面
    chat_element.click()

    # 找到输入框,并输入
    self.weixin_driver.find_element_by_name("输入").send_keys(msg)

    # 点击右下角的发送,发送消息出去
    self.weixin_driver.find_element_by_name("发送(S)").click()
  • 需要注意的是,如果涉及界面的滑动,可以使用「 ActionChains 」移动鼠标,然后使用 win32api 和 win32con 模拟屏幕滑动即可
import win32api
import win32con
from appium import webdriver
from selenium.webdriver import ActionChains

# 模拟屏幕滑动
# 1、移动到某个元素区域
ActionChains(self.weixin_driver).move_to_element(
     self.weixin_driver.find_element_by_name("element_name")).perform()

# 2、滑动界面
# 比如,向上滚动,模拟滑动
win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL, 0, 0, -500)
  • 完成自动化操作后,就可以主动释放资源、关闭 WinAppDriver 服务
# 释放资源及关闭服务
def tearDownFunc(self):
    print("准备退出")
    sleep(2)

    # 1、释放资源
    self.weixin_driver.quit()

    # 2、关闭WinAppDriver应用程序
    os.system(' @taskkill /f /im WinAppDriver.exe')
  • 在实际使用过程中,可能会遇到复杂的桌面应用程序,这时我们可以通过打印驱动对象的「 page_source」元素控制树值,以此来帮助我们进行快速定位元素,进而完善自动化脚本

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

芯片工程师求职题目之验证篇(2)

1. 事件驱动的仿真器和和基于周期的仿真器有什么区别? 事件驱动的仿真器顾名思义就是根据事件(event)触发仿真进行的,在进入一个周期中,它会获取每个事件并通过设计传播求值,直到达到稳定状态的条件,接着进入下一个周…

Android:安卓开发采用Volley网络框架+MySQL数据库,实现从服务器获取数据并展示完成记单词APP

一、功能与要求 实现功能:设计一个记单词APP。服务器采用Tomcat,数据库采用Mysql。实现用户的注册登录功能以及单词的增删改查。 指标要求:实现UI布局;将系统数据保存到Mysql数据库中,并采用Volley网络框架实现从服务…

【机器学习核心总结】什么是随机森林

什么是随机森林 森林里有很多树,随机森林里有很多决策树。 随机森林是决策树的升级版,随机指的是树的生长过程。世上没有两片相同的树叶,随机森林中的树也各不相同。在构建决策树时,我们会从训练数据中有放回的随机选取一部分样本…

Kubernetes service服务的发布 - kube-proxy(负载均衡器)-IPVS

目录 Service Service将内部的pod暴露到外面,让用户可以访问 负载均衡策略: Service 的类型: 案例:Service服务发布案例 扩展:我们在案例再加入一个探针的使用 更改后的my_nginx.yaml文件: 创建Pod&…

ChatGLM2-6B发布,C-Eval超GPT4,支持32k上下文!

自清华大学数据挖掘实验室(THUDM)3月开源ChatGLM-6B已经过去了3个多月,最近他们又带来了性能全面提升的“船新”版本-ChatGLM2-6B。别看名字变化小,其实更新的模型性能是又有量又实用。不了解ChatGLM的小伙伴可以看我这篇文章&…

Java基础之五 反射

通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。 通过反射可以访问的主要描述信息 访问成员变量 常用方法:getFields()、getField(String name)、getDeclaredFields()…

第 353 场LeetCode周赛

A 找出最大的可达成数字 签到题 class Solution { public:int theMaximumAchievableX(int num, int t) {return numt*2;} };B 达到末尾下标所需的最大跳跃次数 动态规划: 定义 p i p_i pi​为跳至 i i i处所需的最大跳跃次数, 有状态转移方程 p i m a x { p j 1 ∣ 0 ≤ j &…

文档管理:PaperPort Professional 14.7 Crack

文档管理变得简单 PaperPort Professional 快速、轻松地访问重要文档对于保持组织平稳运行至关重要。与其浪费时间在文件夹中搜索所需的文件,不如在PC上扫描,转换,组织,组装和共享文档和图像,或者更好的是,…

vue对于数组的数据监听变化和object是不一样的吗?

我们知道vue对于数组的数据监听变化和object是不一样的,因为我们常说的Object.defineProperty是对象上面的方法,所以对于array数组需要实现另外一套变化侦测机制。 今天我们就来研究下。 在哪里收集依赖 array数据设计了新的变化侦测机制,…

阿里云服务器架构X86计算、ARM、GPU/FPGA、裸金属和超级计算集群

阿里云服务器架构有什么区别?X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、超级计算集群有什么区别?阿里云服务器网分享云服务器ECS架构详细说明: 目录 阿里云服务器ECS架构说明 X86计算 ARM计算 GPU/FPGA/ASIC 弹性裸金属服务…

第八章:L2JMobius学习 – 游戏服务GameServer讲解

本章节我们来讲解GameServer服务,首先来查看它的文件结构 ai:游戏角色自动化处理,比如说,自动攻击。 cache:数据缓存,里面就一个HtmCache.java类,缓存HTML文件内容。 communitybbs:b…

【C语言】1-Visual C++ 2010 的简单使用和第一个 C 语言程序

1. Visual C++ 2010 的简单使用 1.1 面板介绍 1.2 新建C语言项目 打开 Visual C++ 2010,点击 New Project 根据下面的图示进行操作,其中需要注意 ③:这里输入的为项目名(建议和我的命名保持一致) ④:这里是项目存放的位置,可以自己选择,最好不要有中文路径(只要是使…

苹果用户要留意?女子FaceTime通话面临巨额骗局,损失高达160万

FaceTime通话是苹果提供的一项服务,可以让使用iOS、iPadOS设备或Mac电脑的用户进行视频或音频通话。只要知道对方的Apple ID,世界各地的苹果设备都可以通过该ID进行呼叫。 据报道,一名居住在上海金山的女性最近遭受了一种新型诈骗&#xff0c…

js逆向补环境-调试工具vscode与nodejs使用之无环境联调

目录 一、啊哈一、Nodejs安装1、nodejs最新版本的安装(windows)2、旧版nodejs更新成最新版本(windows)3、nodejs安装(linux) 二、vscode安装使用(windows)1、下载安装vscode2、vscode运行插件Code Runner安…

多元分类预测 | Matlab基于K近邻算法(KNN)的数据分类预测,多特征输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 基于K近邻算法(KNN)的数据分类预测,多特征输入模型 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,程序可出分类效果图,迭代优化图,混淆矩阵图。 部分源码

MAYA粒子爆炸

创建粒子替代 中心归零 只有一种石头 particleShape1.shitourand(0,5); 设置石头大小 等比例变小 particleShape1.daxiao<<0.2,0.2,0.2>>; 使用变量代替 float $daxiaorand(0.2,0.5); particleShape1.daxiao<<$daxiao,$daxiao,$daxiao>>; 非等比例缩…

【国家标准】GB 7713-87 科学技术报告、学位论文和学术论文编写格式

目 录 1 引言 2 定义 2.1 科学技术报告 2.2 学位论文 2.3 学术论文 3 编写要求 4 编写格式 5 前置部分 5.1 封面 5.2 封二 5.3 题名页 5.4 变异本 5.5 题名 5.6 序或前言 5.7 摘要 5.8 关键词 5.9 目次页 6 主体部分 6.1 格式 6.2 序号 6.3 引言(或绪论)…

基于stm32单片机的智能家居环境监控系统

​一.硬件方案 智能家居环境监控系统的整体电路主要由stm32单片机最小系统&#xff0c;光MQ-2烟雾传感器电路&#xff0c;红外人体检测电路&#xff0c;DS18B20温度传感器&#xff0c;LCD1602显示电路&#xff0c;水泵驱动电路&#xff0c;风扇驱动电路&#xff0c;LED指示灯&…

传输方式的分类【图解TCP/IP(笔记五)】

文章目录 传输方式的分类面向有连接型和无连接型面向有连接型面向无连接型 电路交换与分组交换根据接收端数量分类单播&#xff08;Unicast&#xff09;广播&#xff08;Broadcast&#xff09;多播&#xff08;Multicast&#xff09;任播&#xff08;Anycast&#xff09; 传输方…