• Appium学习日记(三)——Windows系统测试桌面应用


    Appium学习日记(三)——Windows系统测试桌面应用

    一、环境搭建

    1-1、WinAppDriver环境搭建

    (1)开启开发者选项中的“开发人员模式”
    在这里插入图片描述
    (2)Windows sdk下载安装
      下载地址:https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk/

    在这里插入图片描述
      正常安装就行。
    (3)winAppDriver下载
      下载地址:https://github.com/microsoft/WinAppDriver/releases
      任选一个版本,打开如下图,接着根据需求选择合适自己的安装包下载即可。
    在这里插入图片描述
      下载完成后,一键安装即可。

    二、使用Appium连接WinAppDriver

    2-1、启动WinAppDriver

      默认安装路径为:C:\Program Files\Windows Application Driver。点击WinAppDriver.exe。

    2-2、启动Appium

    (1)用管理员的方式打开Appium,设置端口和主机地址,点击“startServer”。
    在这里插入图片描述
    在这里插入图片描述
    (2)最新的Appium Inspector已经和Appium剥离开了,去官网单独下载一个Appium Inspector。解压后直接用管理员的方式点击使用
    在这里插入图片描述
    (3)介绍一下DesiredCapabilities
      DesiredCapabilities 携带了一些配置信息,在启动session的时候是必须提供,如启动模式、apk/app配置、package/activity配置、浏览器配置、键盘配置等。

    描述
    automationName自动化测试的引擎Appium (默认)或者 Selendroid
    platformName使用的手机操作系统iOS, Android, 或者 FirefoxOS
    platformVersion手机操作系统的版本例如 7.1, 4.4
    deviceName使用的手机或模拟器类型iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, 等等… 在 iOS 上,使用 Instruments instruments -s devices 命令可返回一个有效的设备的列表。在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数
    app本地绝对路径或远程 http URL 所指向的一个安装包(.ipa,.apk,或 .zip 文件)。Appium 将其安装到合适的设备上。请注意,如果您指定了 appPackage 和 appActivity 参数(见下文),Android 则不需要此参数了。该参数也与 browserName 不兼容。/abs/path/to/my.apk 或 http://myapp.com/app.ipa
    browserName做自动化时使用的浏览器名字。如果是一个应用则只需填写个空的字符串 'Safari' 对应 iOS'Chrome', 'Chromium', 或 'Browser' 则对应 Android
    newCommandTimeout用于客户端在退出或者结束 session 之前,Appium 等待客户端发送一条新命令所花费的时间(秒为单位)例如 60
    language(Sim/Emu-only) 为模拟器设置语言例如 fr
    locale(Sim/Emu-only) 为模拟器设置所在区域例如 fr_CA
    udid连接真机的唯一设备号例如 1ae203187fc012g
    orientation(Sim/Emu-only) 模拟器当前的方向竖屏 或 横屏
    autoWebview直接转换到 Webview 上下文(context)。默认值为 falsetrue, false
    noReset在当前 session 下不会重置应用的状态。默认值为 falsetrue, false
    fullReset(iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 falsetrue, false

    (4)设置好相关的DesiredCapabilities后,点击Start Session;如下图所示:
    在这里插入图片描述

    2-3、元素定位

    方法名参数描述
    findElementByName(String ) 元素name属性通过元素name属性查找,在Android中一般可以用text代替
    findElementByAndroidUIAutomator(String ) Ui Automator查找代码使用UI Automator来查找元素
    findElementByClassName(String ) 类名,要写全路径:android.weight.TextView通过元素类名查找
    findElementById(String) 元素id,android:id/title通过元素id查找
    findElementByAccessibilityId(String) 元素的contentDescription属性通过contentDescription属性查找
    findEelementByXPath(String) 元素的XPath通过XPath查找
    findElementByCssSelectorWebView专用
    findElementByLinkTextWebView专用
    findElementByPartialLinkTextWebView专用

    注意: 每一个方法对应着一个findElementsBy***方法,后者返回一个Element集合List,表示一个符合查找规则的一个Element集合。

    findElementByName
      在Android中,没有合适的方法可以找到控件的Name属性,但是大多数情况下可以用控件的text代替name。

    findElementByAndroidUIAutomator
      使用UI Automator查找控件

    WebElement el = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");
    
    • 1

    findElementByClassName

    WebElement el = driver.findElementByClassName("android.weight.TextView");
    
    • 1

    findElementById

    WebElement el = driver.findElementById("android:id/title");
    
    • 1

      如果目标设备的API Level低于18则UIAutomatorViewer不能获得对应的Resource ID,只有等于大于18的时候才能使用。

    findElementByAccessibilityId

    WebElement el = driver.findElementByAccessibilityId("menu_add_note_description");
    
    • 1

      Accessibility ID在Android上面就等同于contentDescription

    findEelementByXPath

    WebElement el = driver.findElementByXPath("//android.widget.TextView[contains(@text,'Add note')]");  
    
    • 1

      xPath是一种路径,在uiautomatorviewer中可以查看当前页面的元素层级,XPath就是用来描述这种层级关系的一种路径表达方式,

    findElementByCssSelector
      这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。

    findElementByLinkText
      这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。

    findElementByPartialLinkText
      这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。

    UI Automater定位元素

      UI Automator中主要通过UISelector类查找元素
    通过文本信息定位

    返回值方法名说明用法
    UiSelectortext(String text)根据“控件text属性的内容”构造出UiSelector对象例如,一个控件text的值是“发现”,UiSelector s = new UiSelector().text(“发现”);
    UiSelectortextContains(String text)根据“控件text属性包含的内容”构造出UiSelector对象同上例子:UiSelector s = new UiSelector().textContains(“现”);
    UiSelectortextMatches(String regex)根据“控件text属性正则表达式的内容”构造出UiSelector对象正则表达式语法参考网上资料
    UiSelectortextStartsWith(String text)根据“控件text属性开始的内容”构造出UiSelector对象同上例子:UiSelector s = new UiSelector().textStartsWith(“发”);

    通过description定位

    返回值方法名说明
    UiSelectordescription(String desc)根据“控件content-desc属性的内容”构造出UiSelector对象
    UiSelectordescriptionContains(String desc)包含**
    UiSelectordescriptionMatches(String regex)正则
    UiSelectordescriptionStartsWith(String desc)以**开始

    通过ResourceId定位

    返回值方法名说明
    UiSelectorresourceId(String id)根据资源id获取对象,例如:UiSelector s = new UiSelector().resourceId(“com.tencent.mm:id/b8m”)
    UiSelectorresourceIdMatches(String regex)根据资源id的正则表达式获取对象

    通过类名定位

    返回值方法名说明
    UiSelectorclassName(String className)根据控件类名找到对象
    UiSelectorclassNameMatches(String regex)根据类名的正则表达式获取对象
    UiSelectorinstance(int instance)找到一个拥有相同属性的对象集合中的对象,例如:UiSelector s = new UiSelector().className(“android.widget.TextView”).instance(1);可以找到页面层级中第二个类名为TextView的元素
    UiSelectorindex(int index)用法和上面的instance差不多,谷歌的原文说这个方法是unreliable的,推荐使用instance方法

    通过层级关系

    返回值方法名说明
    UiSelectorfromParent(UiSelector s)获取同一个父控件的其他子控件,即获取兄弟控件
    UiSelectorgetFromParent(UiSelector s)获取同一个父控件的其他子控件,即获取兄弟控件
    UiSelectorchildSelector(UiSelector s)获取子控件
    UiSelectorgetChild(UiSelector s)获取子控件

    使用JUnit组织测试用例
      使用JUnit来组织Appium测试用例,可以添加@Before@Test或者@After等注解来使测试代码的运行变得更加灵活。

      比如在开始测试之前,需要配置Capability和连接Appium服务器,而且一般需要安装应用或者打开应用的某个Activity。这时候可把这些操作放到一个方法中,并且方法添加@Before注解,则在运行的时候,@Before方法会先于@Test方法执行。

      同理,测试结束后需要关闭session,回收资源等等,可以把这些操作放到一个@After方法中,@After方法在所有@Test方法结束之后执行。

    显式等待和隐式等待

      有时候,由于网络或者其他原因,页面跳转之后,某些元素没有立即显示出来,此时查找元素会失败。这种情况就需要引入显式等待隐式等待

    线程等待
      直接使用Thread.sleep();

    隐式等待

    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    
    • 1

      全局等待30秒,不管元素是否已经加载。

    显式等待
      WebDriverWait 显示等待,显示等待时间可以通过 WebDriverWaitutil 来决定,比如这个timeOut是60,如果该元素60s以内出现就不在等待。

    WebDriverWait wait = new WebDriverWait(driver, 60);
        WebElement e= wait.until(new  ExpectedCondition<WebElement>() {
                @Override
                public WebElement apply(WebDriver d) {
                    return d.findElement(By.id("q"));
                }
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

      以下为在Visual Studio下的三个例子。

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Appium.Enums;
    using OpenQA.Selenium.Appium.Service;
    using OpenQA.Selenium.Appium.Windows;
    using System;
    using System.Threading;
    
    namespace PSDemoStartApp
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void StartApplication()
            {
                var capabilities = new AppiumOptions();
                capabilities.AddAdditionalCapability(MobileCapabilityType.App, "D:/Program Files/Notepad++/notepad++.exe");
                capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Windows");
                capabilities.AddAdditionalCapability(MobileCapabilityType.DeviceName, "WindowsPC");
    
                //start the driver
    
                var driver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723/wd/hub"), capabilities);
    
                driver.Close();
                driver.Dispose();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Appium.Enums;
    using OpenQA.Selenium.Appium.Service;
    using OpenQA.Selenium.Appium.Windows;
    using System;
    using System.Threading;
    
    namespace PSDemoStartApp
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void StartApplication()
            {
                var capabilities = new AppiumOptions();
                capabilities.AddAdditionalCapability(MobileCapabilityType.App, "D:/Program Files/Notepad++/notepad++.exe");
                capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Windows");
                capabilities.AddAdditionalCapability(MobileCapabilityType.DeviceName, "WindowsPC");
    
                //start the driver
    
                //var driver = new WindowsDriver(new Uri("http://127.0.0.1:4723/wd/hub"), capabilities);
                var appiumLocalServer = new AppiumServiceBuilder().UsingAnyFreePort().Build();
                appiumLocalServer.Start();
                var driver = new WindowsDriver<WindowsElement>(appiumLocalServer, capabilities);
                Thread.Sleep(2000);
                driver.Close();
                driver.Dispose();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Appium;
    using OpenQA.Selenium.Appium.Enums;
    using OpenQA.Selenium.Appium.Service;
    using OpenQA.Selenium.Appium.Windows;
    using System;
    using System.Threading;
    
    namespace PSDemoStartApp
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void FindElementTest()
            {
                var driver = StartNTApplication();
                var elementFound = driver.FindElementByName("文件(F)");
                Assert.IsTrue(elementFound.Text == "文件(F)");
                var elementFound2 = driver.FindElement(By.Name("文件(F)"));
                Assert.IsTrue(elementFound.Text == elementFound2.Text);
                driver.CloseApp();
            }
            public WindowsDriver<WindowsElement> StartNTApplication()
            {
                var capabilities = new AppiumOptions();
                capabilities.AddAdditionalCapability(MobileCapabilityType.App, "C:/Windows/System32/notepad.exe");
                capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Windows");
                capabilities.AddAdditionalCapability(MobileCapabilityType.DeviceName, "WindowsPC");
    
                //start the driver
    
                //var driver = new WindowsDriver(new Uri("http://127.0.0.1:4723/wd/hub"), capabilities);
                var appiumLocalServer = new AppiumServiceBuilder().UsingAnyFreePort().Build();
                appiumLocalServer.Start();
                var driver = new WindowsDriver<WindowsElement>(appiumLocalServer, capabilities);
                //Thread.Sleep(2000);
                //driver.Close();
                //driver.Dispose();
                return driver;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    面试记录_
    2016年下半年 系统架构设计师 下午论文
    DN-DETR 论文精度,并解析其模型结构 & 2022年CVPR论文
    一篇搞定MyBatisPlus!
    OpenGL-状态机 理解
    浮点数表示法(总结自CS61C和CMU CSAPP)
    Docker三剑客之docker-swarm
    Uni-app 小程序 APP 的广告变现之路:小程序插件
    计算机毕业设计Java服装批发进销存系统(源码+系统+mysql数据库+lw文档)
    linux缓存-利用缓存提高性能的编程技巧
  • 原文地址:https://blog.csdn.net/VicTree/article/details/127685409