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)。默认值为 false true, false
noReset 在当前 session 下不会重置应用的状态。默认值为 false true, false
fullReset (iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 false 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(“com.tencent.mm: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 显示等待,显示等待时间可以通过 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"));
            }
        })

  以下为在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();
        }
    }
}
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);
            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(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<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;
        }
    }
}

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐