Appium学习日记(三)——Windows系统测试桌面应用
一、环境搭建
1-1、WinAppDriver环境搭建
(1)开启开发者选项中的“开发人员模式”

 (2)Windows sdk下载安装
   下载地址:https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk/

   正常安装就行。
 (3)winAppDriver下载
   下载地址:https:///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配置、浏览器配置、键盘配置等。
| 键 | 描述 | 值 | 
| 
 | 自动化测试的引擎 | 
 | 
| 
 | 使用的手机操作系统 | 
 | 
| 
 | 手机操作系统的版本 | 例如 | 
| 
 | 使用的手机或模拟器类型 | 
 | 
| 
 | 
 | /abs/path/to/my.apk 或 http:///app.ipa | 
| 
 | 做自动化时使用的 | 
 | 
| 
 | 用于客户端在退出或者结束  | 例如 | 
| 
 | 
 | 例如  | 
| 
 | 
 | 例如  | 
| 
 | 连接真机的唯一设备号 | 例如  | 
| 
 | 
 | 竖屏 或 横屏 | 
| 
 | 直接转换到 | true, false | 
| 
 | 在当前  | true, false | 
| 
 | (iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 | true, 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查找 | 
| findElementByCssSelector | WebView专用 | |
| findElementByLinkText | WebView专用 | |
| findElementByPartialLinkText | WebView专用 | 
注意: 每一个方法对应着一个findElementsBy***方法,后者返回一个Element集合List,表示一个符合查找规则的一个Element集合。
findElementByName
   在Android中,没有合适的方法可以找到控件的Name属性,但是大多数情况下可以用控件的text代替name。
findElementByAndroidUIAutomator
   使用UI Automator查找控件
WebElement el = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");findElementByClassName
WebElement el = driver.findElementByClassName("android.weight.TextView");findElementById
WebElement el = driver.findElementById("android:id/title");如果目标设备的API Level低于18则UIAutomatorViewer不能获得对应的Resource ID,只有等于大于18的时候才能使用。
findElementByAccessibilityId
WebElement el = driver.findElementByAccessibilityId("menu_add_note_description");Accessibility ID在Android上面就等同于contentDescription
findEelementByXPath
WebElement el = driver.findElementByXPath("//android.widget.TextView[contains(@text,'Add note')]");xPath是一种路径,在uiautomatorviewer中可以查看当前页面的元素层级,XPath就是用来描述这种层级关系的一种路径表达方式,
findElementByCssSelector
   这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。
findElementByLinkText
   这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。
findElementByPartialLinkText
   这个方法是针对WebView容器下面的控件定位的,因为现在针对的是Native App暂时还没有用到,所以先标记下,今后需要的时候加上去。
UI Automater定位元素
  UI Automator中主要通过UISelector类查找元素
通过文本信息定位
| 返回值 | 方法名 | 说明 | 用法 | 
| UiSelector | text(String text) | 根据“控件text属性的内容”构造出UiSelector对象 | 例如,一个控件text的值是“发现”,UiSelector s = new UiSelector().text(“发现”); | 
| UiSelector | textContains(String text) | 根据“控件text属性包含的内容”构造出UiSelector对象 | 同上例子:UiSelector s = new UiSelector().textContains(“现”); | 
| UiSelector | textMatches(String regex) | 根据“控件text属性正则表达式的内容”构造出UiSelector对象 | 正则表达式语法参考网上资料 | 
| UiSelector | textStartsWith(String text) | 根据“控件text属性开始的内容”构造出UiSelector对象 | 同上例子:UiSelector s = new UiSelector().textStartsWith(“发”); | 
通过description定位
| 返回值 | 方法名 | 说明 | 
| UiSelector | description(String desc) | 根据“控件content-desc属性的内容”构造出UiSelector对象 | 
| UiSelector | descriptionContains(String desc) | 包含** | 
| UiSelector | descriptionMatches(String regex) | 正则 | 
| UiSelector | descriptionStartsWith(String desc) | 以**开始 | 
通过ResourceId定位
| 返回值 | 方法名 | 说明 | 
| UiSelector | resourceId(String id) | 根据资源id获取对象,例如:UiSelector s = new UiSelector().resourceId(“:id/b8m”) | 
| UiSelector | resourceIdMatches(String regex) | 根据资源id的正则表达式获取对象 | 
通过类名定位
| 返回值 | 方法名 | 说明 | 
| UiSelector | className(String className) | 根据控件类名找到对象 | 
| UiSelector | classNameMatches(String regex) | 根据类名的正则表达式获取对象 | 
| UiSelector | instance(int instance) | 找到一个拥有相同属性的对象集合中的对象,例如:UiSelector s = new UiSelector().className(“android.widget.TextView”).instance(1);可以找到页面层级中第二个类名为TextView的元素 | 
| UiSelector | index(int index) | 用法和上面的instance差不多,谷歌的原文说这个方法是unreliable的,推荐使用instance方法 | 
通过层级关系
| 返回值 | 方法名 | 说明 | 
| UiSelector | fromParent(UiSelector s) | 获取同一个父控件的其他子控件,即获取兄弟控件 | 
| UiSelector | getFromParent(UiSelector s) | 获取同一个父控件的其他子控件,即获取兄弟控件 | 
| UiSelector | childSelector(UiSelector s) | 获取子控件 | 
| UiSelector | getChild(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);全局等待30秒,不管元素是否已经加载。
显式等待
   WebDriverWait 显示等待,显示等待时间可以通过 WebDriverWait 和 util 来决定,比如这个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(("q"));
            }
        })以下为在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(, "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();
        }
    }
}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(, "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);
            var appiumLocalServer = new AppiumServiceBuilder().UsingAnyFreePort().Build();
            appiumLocalServer.Start();
            var driver = new WindowsDriver<WindowsElement>(appiumLocalServer, capabilities);
            Thread.Sleep(2000);
            driver.Close();
            driver.Dispose();
        }
    }
}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(("文件(F)"));
            Assert.IsTrue(elementFound.Text == elementFound2.Text);
            driver.CloseApp();
        }
        public WindowsDriver<WindowsElement> StartNTApplication()
        {
            var capabilities = new AppiumOptions();
            capabilities.AddAdditionalCapability(, "C:/Windows/System32/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);
            var appiumLocalServer = new AppiumServiceBuilder().UsingAnyFreePort().Build();
            appiumLocalServer.Start();
            var driver = new WindowsDriver<WindowsElement>(appiumLocalServer, capabilities);
            //Thread.Sleep(2000);
            //driver.Close();
            //driver.Dispose();
            return driver;
        }
    }
}                
 
 
                     
            
        













 
                    

 
                 
                    