Appium 测试参考手册 v1.0

目录

  1. 引言

1.1 文档目的
1.2 建议使用者
2.Appium 安装
2.1 客户端安装及用途
2.2 Server(服务端)安装及用途
3.脚本编写
3.1 识别(定位)界面元素
3.2 脚本编写规范
4.案例执行

1 引言

1.1 文档的目的

本文档详细介绍如何通过 Appium 客户端来录制脚本代码,以及如何通过其官方 API 去写一个可执行的测试脚本,最后介绍 Appium 的整个测试流程,来帮助测试人员可以迅速进行移动端的自动化测试。

1.2 建议使用者

通读一下 Appium 的官方文档。

2 Appium 安装(以下内容的安装适用 Windows)

2.1 客户端安装及用途

安装:请根据个人设备(Windows or Mac)选择合适的安装包,安装过程极其简单,下载完后根据提示操作即可。
安装包地址:https://github.com/appium/appium-desktop/releases/tag/v1.10.0
安装成功后,会有一个 appium 的快捷方式。

用途:它主要是实现了 Appium 功能的 WebDriver 协议的客户端 Library,负责与 Appium 服务器建立连接,并将测试脚本的指令发送给 Appium Server(服务器)。它可抓取 app 上定位信息,辅助我们识别(定位)元素。

2.2 Server(服务端)安装及用途

安装:appium 服务端是基于 node.js 实现的 HTTP 服务器,所以安装 appium 需要先安装 Node,然后才能安装appium服务端,可通过cmd 下输入 npm install -g appium 进行安装。
如果npm install -g appium特别慢,无法下载时,可以用国内的镜像 npm —registry registry.cnpmjs.org install -g appium 安装如果失败可以尝试通过cnpm安装appium,首先通过npm命令安装cnpm

  1. npm install -g cnpm --registry=registry.npm.taobao.org

再通过cnpm安装appium

  1. cnpm install -g appium --no-cache

安装成功后,通过 appium -v 查看当前 appium 版本,直接输入 appium 则启动 appium server 端。
最后,打开 Windows 命令提示符,输入“appium-doctor”命令,如果出现以下提示,说明你 Appium 所需要的各项环境都已准备完成。
image.png
特别注意:如果提示:“appium-doctor”不是内部或外部命令,找到 Appium 的安装目录,例如:
C:\Program Files\Appium\node_modules.bin 添加到环境变量 path 下面。

用途:Appium 服务器是 Appium 框架的核心。主要功能是接受 Appium 客户端发起的连接,监听从客户端发送来的命令,将命令发送给 bootstrap.jar 执行,并将命令的执行结果通过 HTTP 应答反馈给 Appium 客户端。

特别注意: 客户端启动手机上的应用时,会开启一个服务,这时就不用启动服务端的服务了。客户端的服务和服务端的服务是完全一样的,只不过客户端启服务是为了我们录制脚本,而服务端则是和Jenkins搭配使用的。

3.测试脚本编写

3.1 识别(定位)界面元素(ReactNative 项目)

一、启动 Appium 客户端,点击 Start Server。如图所示
image.png
然后出现如下界面并点击图示放大镜🔍按钮,如下所示:
image.png
进入了 Desired Capabilities 参数配置界面,如下所示:
image.png
倘若我们已经配置好了 Desired Capabilities, 我们便可以点击 Start Session 启动我们手机端的应用了。
特别注意:配置参数 必须是 Automatic Server 下的 Desired Capabilities。

二、测试 Android 手机的 Desired Capabilities 具体配置
Desired Capabilities: 是一组键值对的集合,它主要通知 Appium 服务器建立需要的 Session, 其中一些设置可以改变 Appium 服务器的运行行为。
image.png
补充:unicodeKeyboard 和 resetKeyboard 是为了防止键盘冲突(手机键盘和 Appium 自带的键盘),不配置这两个参数会导致无法输入中文、英文以及特殊符号等问题。

三、点击Start Session,开始录制脚本
Session:Appium的客户端和服务端之间进行通信都必须在一个Session的上下文中进行。客户端在发起通信的时候首先会发送一个叫作“Desired Capabilities”的JSON对象给服务器。服务器收到该数据后,会创建一个session并将session的ID返回到客户端。之后客户端可以用该session的ID发送后续的命令。
image.png
点击 Start Recording 后,我们开始录制脚本。点击左侧用户名输入框,然后点击右侧的 Tap 按钮,随后点击 Send Keys,弹出输入框,填入我们的内容,点击弹框上的 Send Keys 即可,等待用户名输入完成。再继续密码的输入操作,和用户名一样的方式操作。最后点击登录按钮,然后点击 Tap, 点击暂停,完成本次录制。得到的脚本如下:

image.png

到这儿,恭喜你完成了一次完整的脚本录制。
特别注意: 录制的脚本不可直接拿来当作测试案例。

3.2 脚本编写规范

一、编写脚本
// 以下均是 Java 脚本示例
普通控件(例如:InputItem)定位:

  1. MobileElement elOne = MobileElementdriver.findElementByAccessibilityId("AccessibilityId的值")

按钮组件(例如:Button)定位:

  1. MobileElement elTwo = (MobileElement) driver.findElementByXPath("//android.view.View[contains(@index, 7)]")

二、脚本案例

  1. package cn.agree.fintech.nice;
  2. import java.net.MalformedURLException;
  3. import java.net.URL;
  4. import org.junit.After;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. import org.openqa.selenium.remote.DesiredCapabilities;
  8. import io.appium.java_client.MobileElement;
  9. import io.appium.java_client.android.AndroidDriver;
  10. public class AppTest {
  11. private AndroidDriver driver;
  12. @Before // 对应 api 文档中的 Creat
  13. public void setUp() throws MalformedURLException {
  14. DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
  15. desiredCapabilities.setCapability("platformName", "Android");
  16. desiredCapabilities.setCapability("appPackage", "com.agree.test");
  17. desiredCapabilities.setCapability("appActivity", "com.shellproject.StartActivity");
  18. desiredCapabilities.setCapability("deviceName", "Galaxy Note3");
  19. desiredCapabilities.setCapability("unicodeKeyboard", "True");
  20. desiredCapabilities.setCapability("resetKeyboard", "True");
  21. URL remoteUrl = new URL("http://localhost:4723/wd/hub");
  22. driver = new AndroidDriver(remoteUrl, desiredCapabilities);
  23. }
  24. @Test
  25. public void sampleTest() {
  26. // 休眠函数是为了保证脚本的稳定性且必须放在 try catch 中
  27. try {
  28. Thread.sleep(30000);
  29. } catch (InterruptedException e) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33. // 脚本正文示例
  34. MobileElement el1 = (MobileElement) driver.findElementByAccessibilityId(
  35. "username"); // RN 项目中我们加入的 accessibilityLabel="username"
  36. el1.click(); // 点击输入框的空白位置,然后点击 Tap
  37. el1.sendKeys("wanghuajian"); // 输入值
  38. MobileElement el2 = (MobileElement) driver.findElementByAccessibilityId(
  39. "password");
  40. el2.click();
  41. el2.sendKeys("abc123!");
  42. MobileElement el3 = (MobileElement) driver.findElementByAccessibilityId(
  43. "cnfpwd");
  44. el3.click();
  45. el3.sendKeys("abc123!");
  46. MobileElement el4 = (MobileElement) driver.findElementByAccessibilityId(
  47. "mobile");
  48. el4.click();
  49. el4.sendKeys("15630257145");
  50. MobileElement el5 = (MobileElement) driver.findElementByAccessibilityId(
  51. "email");
  52. el5.click();
  53. el5.sendKeys("15630257145@qq.com");
  54. MobileElement el6 = (MobileElement) driver.findElementByAccessibilityId(
  55. "address");
  56. el6.click();
  57. el6.sendKeys("张江路旁边的哈士奇");
  58. MobileElement el7 = (MobileElement) driver.findElementByXPath("//android.view.View[contains(@index, 7)]");
  59. el7.click();
  60. try {
  61. Thread.sleep(5000);
  62. } catch (InterruptedException e) {
  63. //TODO: handle exception
  64. e.printStackTrace();
  65. }
  66. }
  67. @After // 对应 api 文档中的 End
  68. public void tearDown() {
  69. driver.quit();
  70. }
  71. }

三、多个脚本
多个脚本的编写,可以在同级目录新建文件夹,在文件夹内新建文件放置编写的脚本,即可一一测试。

4 案例流程(Jenkins)

一、在终端启动 appium 服务
image.png

二、在 Jenkins 上进行如下操作
① 拉取代码
② 构建打包(是把 CAP4M 的工程代码打包成 apk 或者 ipa)
③ 把打好的包安装到手机
④ 单元测试

  • 拉取单元测试项目(可从码云、Github、SVN拉取)
  • 编译打包
  • 进行单元测试
  • 出单元测试报告

特别注意:本地执行测试脚本,不做断言处理,我们仅验证脚步编码执行是否畅通。

附件 api 文档

  • Creat // 这部分代码 Appium 会帮我们生成。(前提是我们的参数配置正确) ```java // Java DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, “10.3”); desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, “iPhone Simulator”); desiredCapabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, “XCUITest”); desiredCapabilities.setCapability(MobileCapabilityType.APP, “/path/to/ios/app.zip”);

URL url = new URL(“http://127.0.0.1:4723/wd/hub“);

IOSDriver driver = new IOSDriver(url, desiredCapabilities); String sessionId = driver.getSessionId().toString();

  1. - End // 这部分代码 Appium 会帮我们生成。代表着测试结束或完成。
  2. ```java
  3. // Java
  4. driver.quit();
  • Screenshot // 截屏

    1. // Java
    2. File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
  • Timeouts

① Timeouts // 配置特定类型的操作在中止之前可以执行的时间量

  1. // Java
  2. driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);

② Implicit Wait // 设置驱动程序在搜索元素时应等待的时间

  1. // Java
  2. driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

③ Async Script // 设置允许执行异步执行的异步脚本在中止之前运行的时间(以毫秒为单位)

  1. // Java
  2. driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
  • Geolocation

① Get Geolocation // 获取当前位置

  1. // Java
  2. Location location = driver.location(); // Must be a driver that implements LocationContext

② Set Geolocation // 设置当前位置

  1. // Java
  2. driver.setLocation(new Location(49, 123, 10)); // Must be a driver that implements LocationContext
  • Find Element // 在页面上寻找一个元素

    1. // Java
    2. MobileElement elementOne = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. MobileElement elementTwo = (MobileElement) driver.findElementByClassName("SomeClassName");
  • Find Elements // 在页面上寻找多个元素

    1. // Java
    2. List<MobileElement> elementsOne = (MobileElement) driver.findElementsByAccessibilityId("SomeAccessibilityID");
    3. List<MobileElement> elementsTwo = (MobileElement) driver.findElementsByClassName("SomeClassName");
  • Click // 单击其中心点的元素

    1. // Java
    2. MobileElement el = driver.findElementByAccessibilityId("SomeId");
    3. el.click();
  • Send Keys // 将一系列击键发送到元素

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. element.sendKeys("Hello world!");
  • Clear // 清楚一个元素的值

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. element.clear();
  • Text // 返回元素的可见文本 ```java

// Java MobileElement element = (MobileElement) driver.findElementByClassName(“SomeClassName”); String elText = element.getText();

  1. - Name // 获取元素的标记名称
  2. ```java
  3. // Java
  4. List<MobileElement> element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
  5. String tagName = element.getTagName();
  • Attribute // 获取元素属性的值

    1. // Java
    2. List<MobileElement> element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. String tagName = element.getAttribute("content-desc");
  • Selected // 确定是否选择了表单或类似形式的元素(复选框,选择等等)

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. boolean isSelected = element.isSelected();
  • Enabled // 确定当前是否启用了元素

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. boolean isEnabled = element.isEnabled();
  • Displayed // 确定当前是否显示元素

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. boolean isDisplayed = element.isDisplayed();
  • Location // 确定当前元素在页面或屏幕上的位置

    1. // Java
    2. List<MobileElement> element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. Point location = element.getLocation();
  • Size // 确定元素大小

    1. // Java
    2. List<MobileElement> element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. Dimension elementSize = element.getSize();
  • Rect // 获取元素的尺寸和坐标

    1. // Java
    2. List<MobileElement> element = (MobileElement) driver.findElementByAccessibilityId("SomeAccessibilityID");
    3. Rectangle rect = element.getRect();
  • Location in View // 一旦滚动到视图中,确定元素在屏幕上的位置

    1. // java not supported
  • Submit // 提交 FORM 元素

    1. // Java
    2. MobileElement element = (MobileElement) driver.findElementByClassName("SomeClassName");
    3. element.submit();
  • Scroll // 使用基于手指的动作事件在触摸屏上滚动

    1. // Java
    2. TouchActions action = new TouchActions(driver);
    3. action.scroll(element, 10, 100);
    4. action.perform();
  • Long Press // 使用手指运动事件长按触摸屏

    1. // Java
    2. TouchActions action = new TouchActions(driver);
    3. action.longPress(element);
    4. action.perform();
  • Move // 手指在屏幕上移动

    1. // Java
    2. TouchActions action = new TouchActions(driver);
    3. action.down(10, 10);
    4. action.move(50, 50);
    5. action.perform();