Python + WinAppDriver + Appium 对Windows桌面应用程序进行界面(UI)自动化测试

简述


WinAppDriver是微软官方提供的一款用于做Window桌面应用程序的界面(UI)自动化测试工具,并且支持Appium,而Appium本身就支持多种编程语言,这样我们就可以借助于Appium-Python-Client(Appium的python客户端)使用python来编写测试windows桌面程序的自动化测试脚本。

 

开发者模式设置


1、右键windows操作系统【开始】菜单,点击【设置】,设置界面搜索框输入“开发者”,点击【开发者设置】

 

2、开发者选项界面勾选“开发人员模式”,等待系统配置完成

 

 

 

Appium连接WinAppDriver配置


1、直接点击WinAppDriver.exe,出现这样的画面,就是正常启动了,默认启动的服务器地址是 http://127.0.0.1:4723/

2、运行Appium,启动服务器界面,不点“启动服务器”按钮,点击【File】-> 【New Session Window...】,开启一个新的会话窗口

3、因为我们是不带参数(即默认配置)启动WinAppDriver的(服务器地址为http://127.0.0.1:4723/),【远程路径】修改为“/”,同时在JSON Reprresentation那里添加如下JSON配置参数(这配置表示创建Windows操作系统桌面会话),并保存,这样下次就不用重复添加了

{
  "platformName": "Windows",
  "app": "Root"
}

4、点击【启动会话】,可以看到WinAppDriver运行窗口打印连接成功的日志

 

WinAppDriver支持的查找元素定位方式


Client APILocator StrategyMatched Attribute in inspect.exeExample
FindElementByAccessibilityIdaccessibility idAutomationIdAppNameTitle
FindElementByClassNameclass nameClassNameTextBlock
FindElementByIdidRuntimeId (decimal)42.333896.3.1
FindElementByNamenameNameCalculator
FindElementByTagNametag nameLocalizedControlType (upper camel case)Text
FindElementByXPathxpathAny//Button[0]

上图方法是C#的版本,python版本就是对应的把大写变小写,单词间以下划线(即_)隔开, 如FindElementByAccessibilityId 对应的就是好find_element_by_accessibility_id。

【Matched Attribute in inspect.exe】列表示的是相应查找方法的定位器参数匹配的是inspect.exe(元素侦测工具)显示的元素中的哪个属性,比如accessibility id 匹配的就是inspect.exe中元素的AutomationId属性。inspect.exe这个工具是用来查看运行软件(uwp、win32、win form、wpf)的 UI 元素的 Name、ID、Text 等等。包含在 Windows SDK 中。最新的Microsoft Visual Studio版本默认包含Windows SDK,可以在Windows SDK文件夹下找到该inspect.exe工具,该文件夹通常是C:\Program Files (x86)\Windows Kits\10\bin\x86

关于FindElementByXPath方法的示例,我看的时候感觉有摸不清怎么写xpath,就算配合上面inspect.exe侦测元素图,也还是蒙,我们可以利用调试代码建立会话后,调用driver的page_source属性打印出xml格式的元素树,以上图为例:

self.driver.page_source
<?xml version="1.0" encoding="utf-16"?>
<Window AcceleratorKey="" AccessKey="" AutomationId="" ClassName="#32770" FrameworkId="Win32" HasKeyboardFocus="True" HelpText="" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="对话框" Name="VNC Viewer : Authentication [No Encryption]" Orientation="None" ProcessId="13344" RuntimeId="42.854442" x="0" y="0" width="364" height="102" CanMaximize="False" CanMinimize="False" IsModal="False" WindowVisualState="Normal" WindowInteractionState="ReadyForUserInteraction" IsTopmost="False" CanRotate="False" CanResize="False" CanMove="True" IsAvailable="True">
    <Edit AcceleratorKey="" AccessKey="" AutomationId="1005" ClassName="Edit" FrameworkId="Win32" HasKeyboardFocus="False" HelpText="" IsContentElement="True" IsControlElement="True" IsEnabled="False" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="编辑" Name="" Orientation="None" ProcessId="13344" RuntimeId="42.657824" x="129" y="36" width="150" height="23" />
    <Edit AcceleratorKey="" AccessKey="" AutomationId="1000" ClassName="Edit" FrameworkId="Win32" HasKeyboardFocus="True" HelpText="" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="True" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="编辑" Name="" Orientation="None" ProcessId="13344" RuntimeId="42.2885588" x="129" y="67" width="150" height="24" />
    <Button AcceleratorKey="" AutomationId="1" ClassName="Button" FrameworkId="Win32" HasKeyboardFocus="False" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="按钮" Name="OK" Orientation="None" ProcessId="13344" RuntimeId="42.854288" x="286" y="36" width="68" height="23" />
    <Button AcceleratorKey="" AutomationId="2" ClassName="Button" FrameworkId="Win32" HasKeyboardFocus="False" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="按钮" Name="Cancel" Orientation="None" ProcessId="13344" RuntimeId="42.985372" x="286" y="67" width="68" height="24" />
    <Image AcceleratorKey="" AutomationId="101" ClassName="Static" FrameworkId="Win32" HasKeyboardFocus="False" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="False" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="图像" Orientation="None" ProcessId="13344" RuntimeId="42.1444034" x="12" y="36" width="48" height="48" />
    <Text AcceleratorKey="" AutomationId="65535" ClassName="Static" FrameworkId="Win32" HasKeyboardFocus="False" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="False" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="文本" Name="Username:" Orientation="None" ProcessId="13344" RuntimeId="42.1640712" x="69" y="36" width="53" height="23" />
    <Text AcceleratorKey="" AutomationId="65535" ClassName="Static" FrameworkId="Win32" HasKeyboardFocus="False" IsContentElement="True" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="False" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="文本" Name="Password:" Orientation="None" ProcessId="13344" RuntimeId="42.854286" x="69" y="67" width="53" height="24" />
    <TitleBar AcceleratorKey="" AutomationId="TitleBar" ClassName="" FrameworkId="" HasKeyboardFocus="False" IsContentElement="False" IsControlElement="True" IsEnabled="True" IsKeyboardFocusable="True" IsOffscreen="False" IsPassword="False" IsRequiredForForm="False" ItemStatus="" ItemType="" LocalizedControlType="标题栏" Orientation="None" ProcessId="13344" RuntimeId="42.854442.3.-2147483647.854442.-2.0" x="1" y="3" width="362" height="23" />
</Window>

 

VNC Viewer 连接远程电脑桌面 UI自动化测试的示例代码


 

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@Author: 思文伟
@Date: 2021/03/30 15:49:32
'''
import io
import os
import sys
from appium import webdriver

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(BASE_DIR)

from WinAppUITest.utils.base_testcase import BaseTestCase
from WinAppUITest.utils.test_wrapper import testcase


class VNCViewerTest(BaseTestCase):
    """VNC Viewer 连接远程电脑桌面"""
    @classmethod
    def setUpClass(cls):
        desired_caps = {}
        desired_caps["app"] = r"C:\Users\cfgdc-pc 98\Desktop\vnc-4_1_2-x86_win32_viewer.exe"  # vnc viewer 的执行路径
        server_url = "http://127.0.0.1:4723"
        cls.driver = webdriver.Remote(server_url, desired_caps)

    def setUp(self):
        pass

    @testcase(priority=1, enabled=True, description='使用正确密码连接远程电脑桌面')
    def connect_remote_pc_desktop(self):

        ip = "10.201.15.253"
        pwd = "123456"
        self.sleep(5)  # 等待vnc viewer界面显示出来
        el_ok = self.driver.find_element_by_name("OK")
        el_ip = self.driver.find_element_by_accessibility_id('1001')  # 这个查找方法慎用,AutomationId 这个很有可能是动态值
        el_ip.clear()
        el_ip.send_keys(ip)
        el_ok.click()

        self.sleep(20)  # 上面点击ok后,到下一个界面显示出来需要时间,所以这里设置延时等待
        # for window_handle in self.driver.window_handles: #调试代码
            # self.driver.switch_to.window(window_handle)
            # print("self.driver.title=", self.driver.title)
            # print("self.driver.page_source=", self.driver.page_source)

        # 因为上面点击ok按钮后,界面消失后到弹出下一个界面后,需要切换到下一个界面的窗口,否则直接执行后续的代码会报错
        # 查找并切换到输入密码控件所在的窗口 代码 start -------
        vnc_title = "VNC Viewer : Authentication [No Encryption]"
        for window_handle in self.driver.window_handles:
            self.driver.switch_to.window(window_handle)
            if self.driver.title == vnc_title:
                break
        # 查找并切换到输入密码控件所在的窗口 代码 end   -------

        childrens = self.driver.find_elements_by_xpath("./*")  # 获取当前窗口下的所有子元素
        for c in childrens:
            # print("c.get_attribute("IsEnabled")=", c.get_attribute("IsEnabled"))
            if c.get_attribute("IsEnabled") == "true":  # 通过界面我们知道 只有输入密码框是可编辑的,所以使用该条件来判断是否密码输入框元素
                c.send_keys(pwd)
                break
        self.sleep(10)  # 这里延时是为了 显示输入密码的过程,否则就会执行下面的点击ok按钮,一闪而过
        self.driver.find_element_by_name("OK").click()

    def tearDown(self):
        pass

    @classmethod
    def tearDownClass(cls):
        cls.sleep(2)
        cls.driver.quit()


if __name__ == '__main__':
    VNCViewerTest.run_test()

完整示例代码https://github.com/hotswwkyo/WinAppUITest

  • 11
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值