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

一、环境搭建

1-1、WinAppDriver环境搭建

(1)开启开发者选项中的“开发人员模式”

appium ios 测试 appium测试windows程序_appuim


(2)Windows sdk下载安装

  下载地址:https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk/

appium ios 测试 appium测试windows程序_学习_02


  正常安装就行。

(3)winAppDriver下载

  下载地址:https://github.com/microsoft/WinAppDriver/releases   任选一个版本,打开如下图,接着根据需求选择合适自己的安装包下载即可。

appium ios 测试 appium测试windows程序_学习_03


  下载完成后,一键安装即可。

二、使用Appium连接WinAppDriver

2-1、启动WinAppDriver

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

2-2、启动Appium

(1)用管理员的方式打开Appium,设置端口和主机地址,点击“startServer”。

appium ios 测试 appium测试windows程序_appuim_04


appium ios 测试 appium测试windows程序_学习_05


(2)最新的Appium Inspector已经和Appium剥离开了,去官网单独下载一个Appium Inspector。解压后直接用管理员的方式点击使用

appium ios 测试 appium测试windows程序_学习_06


(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;如下图所示:

appium ios 测试 appium测试windows程序_appuim_07

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;
        }
    }
}