• 桌面应用自动化WinAppDriver入门


    桌面应用自动化WinAppDriver入门

    关于winappdriver

    介绍

    • WinAppDriver全称是Windows Application Driver,它提供了一些API,使得用户可以像selenium操作web一样来操作windows的应用程序
    • 它支持的系统是Windows 10 (Home and Pro) 和Windows Server 2016
    • 源码暂未开源
    • WinAppDriver可以独立运行,也可以作为appium的一个插件来使用

    支持应用类型

    • UWP – Universal Windows Platform, also known as Universal Apps or Modern Apps, It's Microsoft’s latest desktop application technology. It's XAML based. Only runs on Windows 10 machines

    • WPF - also XAML based, much more mature, runs on any Windows version and has been around since 2006.

    • WinForms - one of the older technologies, now found mostly on legacy applications.

      WPF和WinForms 是两套界面渲染方式。一个是对传统windows界面元素的封装,通过gdi绘制。另一个是全新的dx渲染绘制的界面,也脱离了对传统windows控件的依赖,没有历史包袱,理论上可以展现更炫酷的界面。
      
    • MFC/Classic Windows - MFC is a UI library normally paired with Win32 applications. This option is normally chosen when more efficiency is needed with low-level C++ handling or when supporting non-Microsoft platforms.

    资源

    素材 地址 说明
    FlaUInspect https://github.com/FlaUI/FlaUInspect/releases 定位工具
    WinAppDriver https://github.com/microsoft/WinAppDriver/releases/tag/v1.2.1
    UIRecorder https://github.com/microsoft/WinAppDriver/tree/master/Tools/UIRecorder 定位工具
    inspect 微软官方工具集成于 Windows SDK 定位工具
    1. UIRecorder(下文不涉及,仅供参考与备忘)
    1. Open WinAppDriverUIRecorder.sln in Visual Studio
    2. Select Debug > Start Debugging or simply Run

    支持的定位方式

    Client API Locator Strategy Matched Attribute in inspect.exe Example
    FindElementByAccessibilityId accessibility id AutomationId AppNameTitle
    FindElementByClassName class name ClassName TextBlock
    FindElementById id RuntimeId (decimal) 42.333896.3.1
    FindElementByName name Name Calculator
    FindElementByTagName tag name LocalizedControlType (upper camel case) Text
    FindElementByXPath xpath Any //Button[0]

    配置

    开启windows的开发者模式

    • 你没看错,不是手机,windows也有
    • 第一步:搜开发者设置
    • 第二步:打开开发人员模式

    • 第三步:确认启用

    启动winappdriver

    • 不开启开发人员模式的提示

      C:\Program Files (x86)\Windows Application Driver>WinAppDriver.exe
      Developer mode is not enabled. Enable it through Settings and restart Windows Application Driver
      Failed to initialize: 0x80004005
      
    • 开启后启动winappdriver

      C:\Program Files (x86)\Windows Application Driver>WinAppDriver.exe
      Windows Application Driver listening for requests at: http://127.0.0.1:4723/
      Press ENTER to exit.
      
    • 还可以这样启动

      WinAppDriver.exe 4727
      WinAppDriver.exe 10.0.0.10 4725
      WinAppDriver.exe 10.0.0.10 4723/wd/hub   # 推荐
      

    实例

    appium-python-client 版本不要用2.0+,此处是1.2.0

    记事本

    • 比如记事本

      from appium import webdriver
      des_cap = {}
      des_cap['app'] = r'C:\Windows\System32\notepad.exe'
      driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                                desired_capabilities=des_cap)
      driver.implicitly_wait(5)
      driver.find_element_by_name('文件(F)').click()
      from time import sleep
      sleep(2)
      driver.find_element_by_name('保存(S)	Ctrl+S').click()
      # driver.find_element_by_name('退出(X)').click()
      sleep(1)
      import pyautogui
      pyautogui.PAUSE = 0.5
      pyautogui.typewrite(r'D:\hello.txt')
      pyautogui.press('enter')
      
    • 这里的难点是保存(S) Ctrl+S的获取

    • 这里需要用到inspect.exe

    计算器

    • 你可能会写这样的代码
    from appium import webdriver
    des_cap = {}
    des_cap['app'] = r'C:\Windows\System32\calc.exe'
    driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                              desired_capabilities=des_cap)
    driver.implicitly_wait(5)
    
    • 但会报错
    Traceback (most recent call last):
      File "D:/demo_calc.py", line 5, in 
        desired_capabilities=des_cap)
      File "D:\Python37\lib\site-packages\appium\webdriver\webdriver.py", line 157, in __init__
        AppiumConnection(command_executor, keep_alive=keep_alive), desired_capabilities, browser_profile, proxy
      File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 157, in __init__
        self.start_session(capabilities, browser_profile)
      File "D:\Python37\lib\site-packages\appium\webdriver\webdriver.py", line 226, in start_session
        response = self.execute(RemoteCommand.NEW_SESSION, parameters)
      File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
        self.error_handler.check_response(response)
      File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
        raise exception_class(message, screen, stacktrace)
    selenium.common.exceptions.WebDriverException: Message: Failed to locate opened application window with appId: C:\Windows\System32\calc.exe, and processId: 4472
    
    进程已结束,退出代码为 1
    
    
    • 打开计算器,然后在powershell中执行如下命令
    Get-StartApps |Select-String "计算器"
    # 输出
    @{Name=计算器; AppID=Microsoft.WindowsCalculator_8wekyb3d8bbwe!App} # 你要的是这里的AppID # 同理,记事本你也可以得到其appid,并自动化
    
    • 代码
    from appium import webdriver
    des_cap = {}
    des_cap['app'] = r'Microsoft.WindowsCalculator_8wekyb3d8bbwe!App'
    driver = webdriver.Remote(command_executor='http://127.0.0.1:4723/wd/hub',
                              desired_capabilities=des_cap)
    driver.implicitly_wait(5)
    driver.find_element_by_name('一').click() # 这些定位你仍然需要inspect
    driver.find_element_by_name('二').click()
    driver.find_element_by_name('加').click()
    driver.find_element_by_name('三').click()
    driver.find_element_by_name('四').click()
    driver.find_element_by_name('等于').click()
    # 通过inspect 获取 automationID 
    print(driver.find_element_by_accessibility_id('CalculatorResults').text) # 得到的是   ·显示为 46·  你仍然要处理才能做测试
    
    driver.quit()
    
    • 就写这么多了,你可以结合你的应用来尝试,封装。我就带到这里。

    计算器测试(官网)

    我没跑,仅供参考,你可以认为是为了增加篇幅

    # https://raw.githubusercontent.com/microsoft/WinAppDriver/master/Samples/Python/calculatortest.py
    import unittest
    from appium import webdriver
    
    class SimpleCalculatorTests(unittest.TestCase):
    
        @classmethod
    
        def setUpClass(self):
            #set up appium
            desired_caps = {}
            desired_caps["app"] = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
            self.driver = webdriver.Remote(
                command_executor='http://127.0.0.1:4723',
                desired_capabilities= desired_caps)
    
        @classmethod
        def tearDownClass(self):
            self.driver.quit()
    
        def getresults(self):
            displaytext = self.driver.find_element_by_accessibility_id("CalculatorResults").text
            displaytext = displaytext.strip("Display is " )
            displaytext = displaytext.rstrip(' ')
            displaytext = displaytext.lstrip(' ')
            return displaytext
    
    
        def test_initialize(self):
            self.driver.find_element_by_name("Clear").click()
            self.driver.find_element_by_name("Seven").click()
            self.assertEqual(self.getresults(),"7")
            self.driver.find_element_by_name("Clear").click()
    
        def test_addition(self):
            self.driver.find_element_by_name("One").click()
            self.driver.find_element_by_name("Plus").click()
            self.driver.find_element_by_name("Seven").click()
            self.driver.find_element_by_name("Equals").click()
            self.assertEqual(self.getresults(),"8")
    
        def test_combination(self):
            self.driver.find_element_by_name("Seven").click()
            self.driver.find_element_by_name("Multiply by").click()
            self.driver.find_element_by_name("Nine").click()
            self.driver.find_element_by_name("Plus").click()
            self.driver.find_element_by_name("One").click()
            self.driver.find_element_by_name("Equals").click()
            self.driver.find_element_by_name("Divide by").click()
            self.driver.find_element_by_name("Eight").click()
            self.driver.find_element_by_name("Equals").click()
            self.assertEqual(self.getresults(),"8")
    
        def test_division(self):
            self.driver.find_element_by_name("Eight").click()
            self.driver.find_element_by_name("Eight").click()
            self.driver.find_element_by_name("Divide by").click()
            self.driver.find_element_by_name("One").click()
            self.driver.find_element_by_name("One").click()
            self.driver.find_element_by_name("Equals").click()
            self.assertEqual(self.getresults(),"8")
    
        def test_multiplication(self):
            self.driver.find_element_by_name("Nine").click()
            self.driver.find_element_by_name("Multiply by").click()
            self.driver.find_element_by_name("Nine").click()
            self.driver.find_element_by_name("Equals").click()
            self.assertEqual(self.getresults(),"81") 
    
        def test_subtraction(self):
            self.driver.find_element_by_name("Nine").click()
            self.driver.find_element_by_name("Minus").click()
            self.driver.find_element_by_name("One").click()
            self.driver.find_element_by_name("Equals").click()
            self.assertEqual(self.getresults(),"8")
    
    if __name__ == '__main__':
        suite = unittest.TestLoader().loadTestsFromTestCase(SimpleCalculatorTests)
        unittest.TextTestRunner(verbosity=2).run(suite)
    
  • 相关阅读:
    Nginx 实战教程
    软件测试,面试题——水杯测试用例
    vue的双向绑定原理
    十四、SpringBoot原理——SpringBoot应用是怎么启动的?从创建容器到运行容器,逐行分析完整过程
    Android学习笔记 50. Android 多媒体技术——SoundPool播放音效
    前端面试题
    单例 懒汉式
    动态数组【python】
    AS3933国产替代SI3933 125kPKE车钥匙方案
    U231683 younger 永存
  • 原文地址:https://www.cnblogs.com/wuxianfeng023/p/17269050.html