前言
此文章 偏向于实操
appium支持在不同平台上(windows,linux、mac) - 使用测试脚本(支持不同语言C #,json,Ruby等等) - 模拟测试各个平台的app(web、windows、mobile等)运行情况,支持ios和安卓平台上的原生应用,web应用和混合运用
appium类库封装了标准Selenium客户端类库,为用户提供所有常见的JSON格式selenium命令以及额外的移动设备控制相关的命令,如多点触控手势和屏幕朝向。
一、 Appium介绍
官网:http://appium.io/docs/cn/about-appium/intro/
这里主要是windows平台下的安装和使用。
1.1 设计理念
1.1.1 使用系统自带的自动化框架
使用各个系统自带的自动化框架可以让appium 独立运行
- 不需要把 Appium 特定的或者第三方的代码编译进应用
- 不用为了自动化而重新编译或修改应用
- 各个系统使用的自动化框架:
iOS 9.3 及以上: 苹果的 XCUITest
iOS 9.3 及以下: 苹果的 UIAutomation
Android 4.3+: 谷歌的 UiAutomator / UiAutomator2
Android 2.3+: 谷歌的 Instrumentation. (通过绑定独立的项目—— Selendroid 提供对 Instrumentation 的支持)
Windows: 微软的 WinAppDriver
1.1.2 支持多种语言 --WebDriver API
把各种系统本身提供的框架包装进一套 API —— WebDriver API 中
WebDriver(也叫「Selenium WebDriver」)。
在WebDriverAPI中,规定了一个客户端-服务器协议(称为 JSON Wire Protocol),按照这种客户端-服务器架构,可以使用任何语言编写的客户端向服务器发送适当的 HTTP 请求。
Appium & WebDriver 客户端在技术上而言不是「测试框架」,而是「自动化程序库」
1.2 架构
1.2.1 客户端 / 服务器架构![每个平台的驱动](https://i-blog.csdnimg.cn/blog_migrate/4990dbc39335a75233ba0157ed155bbe.png)
Appium 的核心一个是暴露 REST API 的 WEB 服务器。它接受来自客户端的连接,监听命令并在移动设备上执行,答复 HTTP 响应来描述执行结果
1.2.2 Appium服务器
Appium 是一个用 Node.js 写的服务器。可以从源码构建安装或者从 NPM 直接安装:
$ npm install -g appium
$ appium
- 它监听符合API规范,从WebDriver 传入的HTTP request。
- WebDriver是一个W3C规范,Appium团队为该协议添加了一些扩展,使其适用于web浏览器,同时也适用在任何设备上测试的任何应用程序。
- Appium Server服务器需要在Node.js web服务器中运行。
- Node.js web服务器可以在运行测试之前在本地机器上启动,也可以托管Appium服务器-让它作为运行测试的一部分。
1.2.3 Appium 客户端
Appium 客户端,不同客户端支持不同语言,来发起http命令。比如postman,Appium server gui等等
- 让Appium客户端与Appium Server服务器交互
- 解读WebDriver协议,将WebDriver协议转换为我们可以轻松使用的客户端库。
Appium提供了相应客户端的库。比如C# 有NuGet包。
1.2.4 会话(Session)
自动化始终在一个会话的上下文中执行。
通过客户端程序库以各自的方式发起与服务器的会话,但最终都会发给服务器一个 POST /session 请求,请求中包含一个被称作「预期能力(Desired Capabilities)」的 JSON 对象。这时服务器就会开启这个自动化会话,并返回一个用于发送后续命令的会话 ID。
1.2.5 预期能力(Desired Capabilities)
预期能力(Desired Capabilities)是一些发送给 Appium 服务器的键值对集合(比如 map 或 hash),它告诉服务器我们想要启动什么类型的自动化会话。
也有许多能力(Capabilities)可以修改服务器在自动化过程中行为。例如,我们可以将 platformName 能力设置为 iOS,以告诉 Appium 我们想要 iOS 中的应用会话,而不是 Android 或者 Windows 应用会话
二、环境配置
-
安装 npm添加链接描述, https://nodejs.org/en/
-
安装Appium:Appium 有命令行版本和桌面版本。可以两个都装上,桌面版本:在appium官网下载并安装Appium。命令行版本,管理员模式运行cmd:
npm install -g appium
可能需要设置网络代理。 -
安装 node.js, https://nodejs.org/en/download/
-
安装 UIRecorder ,https://github.com/Microsoft/WinAppDriver/releases
-
安装结束后,在cmd界面输入“appium-doctor”检查是否缺少东西。
-
电脑启用“开发者模式”
-
添加环境变量
-
安装各平台应用的驱动程序,通过驱动程序,Appium server才能将我们的测试命令翻译给Appium客户端以及应用
- WinAppDriver - Windows平台的驱动程序。针对windows应用自动化 WinAppDriver
- UiAutomator2 - Android,它是Android SDK 安装包的一部分,安装 Java and Android SDK后就可以运行了
- XCUITest - Mac,ios 研发需要Xcode,Xcode只适用于Mac
- 安装Appium inspector。用来查看、定位界面元素。如果使用有问题,可以去github上搜索:https://github.com/appium/appium-desktop/issues
Appium Inspector 有两种版本,
-
桌面app,下载链接https://github.com/appium/appium-inspector/releases
- Appium 1.22版本之前都附带了Inspector 工具,入口在打开之后的搜索图标里(如下图),新版的inspector已经和Appium server不在一起了,需要单独安装。
-
web应用,由Appium Pro托管。直接打开网页就可以 https://inspector.appiumpro.com/
这两个应用程序有完全相同的功能,开网页版会更容易,并节省磁盘空间,同时可以保持多个标签打开!
需要注意的是Appium Inspector设计为默认使用Appium 2.0 (W3C WebDriver协议)。因此,如果是从Appium Desktop(默认情况下设计为使用Appium 1.x)迁移,可能会有一些不同的地方
appium-doctor提示问题以及解决办法:
2.1ANDROID_HOME is not set
解决办法
- 安装过adb的可以在系统变量-path中找到adb的安装路径(因为我用自己安装的路径,缺少android.bat文件,所以我这里解决办法是采用adb路径是安装vs2022时顺带安装的-勾选移动应用开发,包含AndroidSDK项)
- 电脑-高级系统设置-系统变量-新增变量ANDROID_HOME ,值设置为adb 文件夹的路径。
- adb完整路径是C:\Microsoft\AndroidSDK\25\platform-tools,ANDROID_HOME路径设置为C:\Microsoft\AndroidSDK\25
2.2 JAVA_HOME is not set
解决办法:
- 在系统变量中找到找到JDK的安装路径
- 新建变量JAVA_HOME,JDK的路径。这里直接复制完整路径即可。
成功解决之后再次测试appium-doctor,提示全部ok
✔ ANDROID_HOME is set to "C:\Microsoft\AndroidSDK\25"
✔ JAVA_HOME is set to "C:\Program Files\Microsoft\jdk-11.0.12.7-hotspot\bin."
✔ ADB exists at C:\Microsoft\AndroidSDK\25\platform-tools\adb.exe
✔ Android exists at C:\Microsoft\AndroidSDK\25\tools\android.bat
✔ Emulator exists at C:\Microsoft\AndroidSDK\25\tools\emulator.exe
✔ Android Checks were successful.
✔ All Checks were successful
(node:25404) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
三、Appium - 测试程序详细解析
一个简单的自动化程序主要分为启动、交互。
不管哪个客户端,启动的步骤和所需要的参数都是一样的。
启动前要设置初始化参数,告知服务器启动哪一个应用app,在哪个平台,用哪个版本
交互要确认交互的对象 - 哪一个ui元素,交互的动作,以及如何判断动作结束
3.1 Appium 服务器初始化参数(Capability)
AppiumOptions是Appium中一个关键类
在启动应用时可以设置这些类中的这些参数 http://appium.io/docs/cn/writing-running-appium/caps/#appium-capability
3.1.1 Windows应用设置参数
keyName | 描述 | Value |
---|---|---|
appiumOptions.App | 应用 | exe本地绝对路径_或_应用id |
appiumOptions.PlatformName | 操作系统 | “windows”; |
appiumOptions.DeviceName | 设备类型 | “windowsPC”; |
上面这三个是Windows应用必须要设置的
3.1.2 Android应用设置参数
keyName | 描述 | Value |
---|---|---|
platformName | 使用的手机操作系统 | iOS, Android等 |
platformVersion | 手机操作系统的版本 | 例如 7.1, 4.4 |
deviceName | 使用的手机或模拟器类型 | adb devices 命令查看当前设备名称。在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数。 为确保在连接多个设备时连接到正确的 Android 设备,请使用 udid 功能。 |
appActivity | 指从你的包中所要启动的 Android acticity。他通常需要在前面添加. (例如 使用 .MainActivity 代替 MainActivity) | MainActivity, .Settings |
appPackage | 运行的 Android 应用的包名 | com.example.android.myApp, com.android.settings |
app | 本地绝对路径_或_远程 http URL 所指向的一个安装包(.ipa,.apk,或 .zip 文件)。Appium 将其安装到合适的设备上。请注意,如果您指定了 appPackage 和 appActivity 参数(见下文),Android 则不需要此参数了。该参数也与 browserName 不兼容。 | /abs/path/to/my.apk 或 http://myapp.com/app.ipa |
3.2 UI元素定位与交互
如果是WPF程序,在该控件的Automation里面可以找到对应的设置,比如Name,AccessibilityID。
在inspector 里面,可以看到界面元素具体的值
http://appium.io/docs/en/commands/element/find-elements/index.html#selector-strategies
method | 描述 | Value |
---|---|---|
ID | Native element identifier. resource-id for android; name for iOS. | |
AccessibilityID | AutomationID | |
Name | 组件的名称 | |
class Name | ui组件的类型 | BUTTON,MENUBAR等等 |
xpath | 路径定位,依赖元素绝对路径或相关属性定位。不太推荐这种方式 |
四、Appium实战 之启动应用
4.1 通过Inspector启动 - 记事本应用
Appium inspector是一个软件,通过他可以查看界面上的所有元素信息,比如某个按键的名字、控件类型、xy坐标,等等
通过简单设置Appium inspector中的参数,快速启动应用,一方面为后面定位控件元素做好准备,一方面可以通过启动应用所需要的参数,参考到自动化程序中。
-
管理员模式启动
Appium server
,
可以管理员启动桌面版Appium Server GUI.exe,输入Host127.0.0.1和端口4723。
也可以通过管理员模式启动cmd,输入appium
,启动命令行版本
因为inspector(或者其他客户端)与 应用(或者模拟器)之间的通讯交互都需要通过Appium server来传达与翻译。所以要先启动Appium server。
后续交互历史记录在Appium server界面也可以看到详细信息。
-
管理员模式启动
Appium Inspector
,设置Remote path
如果Appium版本是1.x 而inspector 版本是新的,就需要设置远端路径 - Remote path 为/wd/hub
如果Appium 版本是2.x 则不用设置
Appium版本为 v1.22.3,所以需要设置
- wd 可以理解是WebDriver 的缩写
- hub 是指主(中心) 节点,在selenium 分布式里中心节点
![在这里插入图片描述](https://img-blog.csdnimg.cn/edec3033d4b54cfe8313ae5481ceafe2.png
- 添加
Capabilities
在Desired Capabilities 下面,依次添加需要启动应用的信息。
app:要启动的应用,这里添加notepad.exe的路径
deviceName:启动的设备
platformName:这个应用所需要使用的平台
这三个信息是必要的。告诉Appium inspector我们需要在何种环境下启动何种应用
右边会自动将我们填入的信息转换成JSON 表达方式
点击save,保存现在的信息。 - 点击
Start Session
启动session后,inspector会启动记事本应用,
- 左侧界面预览区,是和当前应用同步界面的预览画面,不会实时更新。需要手动点击刷新按钮来同步画面。但是在预览区点击按钮,实际打开的应用会实时同步操作。
- App Source,查看当前界面元素信息,这些信息可以用来帮助我们在写自动化时定位某个界面元素。
五、Appium实战 之编写Mstest 自动化程序
自动化测试程序是模拟应用启动、运行,以及其他的一些特定操作。
所以基于inpector启动应用的流程,我们可以在自己加一些操作,比如输入字符串,保存文档等。
我这里是对自己写的WPF应用进行自动化测试,先在文本框中输入字符串,然后保存文档。
5.1 新建MSTest 测试项目
,或者单元测试项目
5.2 添加NuGet包
项目上右键 - NuGet包管理 - 搜索并添加NuGet包,需要添加以下三个:
- Microsoft.WinAppDriver.Appium.WebDriver
- Selenium.WebDriver
- Selenium.Support
在安装时,注意看下面的依赖项 版本说明,比如.Appium.WebDriver,需要Selenium 包相关版本为3.8.0+。工具-程序包管理控制台, 输入Get-Package
获取当前项目的NuGet包信息
我安装的版本信息如下,
- Appium.WebDriver {5.0.0-alpha} NodepadTest
- Selenium.WebDriver {4.0.0} NodepadTest - Selenium.Support {4.0.0} NodepadTest
官网Samples项目版本如下 (Appium官方样例代码下载地址:https://github.com/Microsoft/WinAppDriver/tree/v1.0#using-appium
)
- Microsoft.WinAppDriver.Appium.We… {1.0.1-Preview} NotepadCalculatorTest
- Selenium.Support {3.8.0} NotepadCalculatorTest
- Selenium.WebDriver {3.8.0} NotepadCalculatorTest
Appium版本更新的时候,会优化很多功能,如果报一些错误,可以试试把版本改一改。
- Microsoft.WinAppDriver.Appium.WebDriver 这是一个用于Appium,临时的Selenium WebDriver的扩展,它实现了Windows应用程序驱动程序(WinAppDriver)的操作API功能。这仅用于预览目的。 Microsoft WinAppDriver 提供
- Appium.WebDriver - Selenium Webdriver extension for Appium. 由Appium提供
https://www.nuget.org/packages 可以搜索关于NuGet包的相关信息
这两个包选择一个使用,我这里选择的- Appium.WebDriver {5.0.0-alpha} NodepadTest
5.3 添加session
- 添加using 引用库
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Service;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium;
using System;
using System.Threading;
using OpenQA.Selenium.Appium.Interactions;
using OpenQA.Selenium.Interactions;
using System.Collections.Generic;
using OpenQA.Selenium.Support.UI;
- 添加session 启动function,在method下调用这个函数的话,就可以启动该Application了。我这里用的是我自己写的一个WPF应用。可以用notepad.exe
public WindowsDriver<WindowsElement> StartNodepadApplication()
{
//1.add capabilities
var appiumOptions = new AppiumOptions();
//appiumOptions.App = @"C:\Windows\System32\notepad.exe";//notepad
appiumOptions.App = "D:\\test\\Appium\\WPFApplication\\AppiumMyApp\\AppiumMyApp\\bin\\x64\\Release\\net6.0-windows\\AppiumMyApp.exe";
appiumOptions.PlatformName = "windows";
appiumOptions.DeviceName = "windowsPC";
//2.start the driver
var appiumLocalServer=new AppiumServiceBuilder().UsingAnyFreePort().Build();
appiumLocalServer.Start();
var driver = new WindowsDriver<WindowsElement>(appiumLocalServer, appiumOptions);
//return the sever session
return driver;
}
- 完善TestMethod,定位界面元素,并进行交互操作
- 点击clear button
- 点击编辑button
- 发送字符串到文本框
- 点击save button
- 建立DefaultWait,每500ms轮询一次,查看是否弹出了保存文件的对话框,我这里用来界面出现保存button ,如果出现表示前面的步骤执行结束。才会继续执行后续的动作
- 同样建立第二个DefaultWait,等到界面弹出一个对话框 ,包含一个元素Name为“文件已导出”,表示文件已经保存完毕了。
[TestMethod]
public void TestWaitForProgressBar()
{
//start session
var session = StartNodepadApplication();
// FindUIElementMethod1 -Name,click clear button
var clearButton = session.FindElementByName("Clear");
clearButton.Click();
// FindUIElementMethod2 -AccessibilityId, click button
var textBox = session.FindElementByAccessibilityId("MyTextBoxID");
textBox.Clear();
//SendKeys
textBox.SendKeys("-----------------------------------------\n");
textBox.SendKeys("******************************************\n");
textBox.SendKeys("my name is jerry\n");
//click save
var saveButton= session.FindElementByName("Save");
saveButton.Click();
//Wait for the progress to process for a while.untill Element appear or disappear
//1.add a DefaultWait,Poll once every 500ms
var wait = new DefaultWait<WindowsDriver<WindowsElement>>(session)
{
Timeout = TimeSpan.FromSeconds(60),
PollingInterval = TimeSpan.FromMilliseconds(500)
};
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
//界面能找到,说明前面动作已经执行完毕
wait.Until(d => d.FindElementByName("保存(S)"));
//click save button in SaveFileDialog
var dialogSavebutton = session.FindElementByName("保存(S)");
dialogSavebutton.Click();
//2.
var wait2 = new DefaultWait<WindowsDriver<WindowsElement>>(session)
{
Timeout = TimeSpan.FromSeconds(60),
PollingInterval = TimeSpan.FromMilliseconds(500)
};
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
//find element to verify save done
wait.Until(d =>
{
return d.FindElementByName("文件已导出");
});
session.FindElementByName("确定").Click();
textBox = session.FindElementByAccessibilityId("MyTextBoxID");
textBox.Clear();
textBox.SendKeys("file save done this is second time I am here-\n");
session.Close();
}
项目右键-运行测试-可以看到会开始执行自动化测试。
六、编写android自动化应用测试程序
6.1 inspector 连接真机
6.1.1获取连接真机app的相关参数
准备工作:手机开启开发者模式
,(一般连续点击系统版本5下),开启usb 调试模式
最好是能使用root 命令的手机,因为我在使用普通手机时,出现了连接不上的问题
第三章提到过,安卓应用启动需要设置以下Capabilities,获取方式标注在了右边
可参考链接:https://blog.csdn.net/u012028250/article/details/120371345
keyName | 描述 | adb 命令 |
---|---|---|
platformName | 手机操作系统 | Android |
platformVersion | 操作系统版本 | adb shell getprop ro.build.version.release ![]() |
deviceName | 手机或模拟器类型 | adb devices ![]() |
appPackage | 运行的 Android 应用的包名 | 手机上打开要测试的app,输入 adb shell "dumpsys window | grep mCurrentFocus" ![]() |
appActivity | 从包中所要启动的 Android acticity | 同上 |
appPackage获取方式有如下几种:package都是com.xxx
adb shell pm list packages
列出手机上所有的包,找到所需要的包名adb shell am monitor
获取当前应用程序包名
appActivity获取方式:
- adb shell dumpsys activity | findstr “mResume”
com.sec.android.app.camera/.Camera t243} ---即appPackage / appActivity
adb shell "dumpsys window \| grep mCurrentFocus"
mCurrentFocus=Window{c22cf8f u0 com.sec.android.app.camera/com.sec.android.app.camera.Camera} ---即appPackage / appActivity
获取之后填入到inspector中
图片中SM-A336B
是通过adb shell getprop ro.product.model
获取的,指的是手机型号,可填可不填。
appium:automationName:指以什么方式解析界面元素UiAutomator2
填完之后,点击start session,手机会自动安装appium 相关软件,然后就可以启动手机中应用,并且获取界面控件元素了。
6.1.1查看界面元素信息
6.2 MSTest测试程序连接真机
6.2.1 参考inspector启动应用
private AndroidDriver<AndroidElement> StartApp()
{
System.Environment.SetEnvironmentVariable("ANDROID_HOME", @"C:\\Microsoft\\AndroidSDK\\25");
System.Environment.SetEnvironmentVariable("JAVA_HOME", @"C:\\Program Files\\Microsoft\\jdk-11.0.12.7-hotspot");
//connect to a device or emulator
var capabilities = new AppiumOptions();
capabilities.DeviceName=@"SM-A336B-58f407b9db347ece";
//capabilities.DeviceName = @"58f407b9db347ece";
capabilities.AutomationName = @"UiAutomator2";
capabilities.PlatformName = "Android";
capabilities.PlatformVersion = "12";
//specifying which app we want to install or launch
capabilities.AddAdditionalAppiumOption("appPackage", "com.sec.android.app.camera");
capabilities.AddAdditionalAppiumOption("appActivity", "com.sec.android.app.camera.Camera");
//specify startup flags appium sever to execute adb shell commands
var serveroptions = new OptionCollector();
var relaxedSecurityOption = new KeyValuePair<string, string>("--relaxed-security", "");
serveroptions.AddArguments(relaxedSecurityOption);
var _appiumLocalService = new AppiumServiceBuilder().UsingAnyFreePort().WithArguments(serveroptions).Build();
//start the service
_appiumLocalService.Start();
var driver = new AndroidDriver<AndroidElement>(_appiumLocalService, capabilities);
return driver;
}
6.2.1 完善TestMethod
[ClassCleanup]//clear up local service
static public void CleanUp()
{
_appiumLocalService?.Dispose();
_appiumLocalService = null;
}
[TestMethod]
public void TestListInstallPackage()
{
AndroidDriver<AndroidElement> driver = StartApp();
//use shell command to list all installed package on the device
string script = "mobile:shell";
var arguments = new Dictionary<string, string>
{
{"command","pm list package" },
{ "----show-versioncode",""},
};
var list = driver.ExecuteScript(script, arguments);
Assert.IsNotNull(list);
Console.Write(list);
}
然后点击运行测试,就可以看到手机相机启动了。