Use Appium to make Android functional automation testing fly

foreword

I have been doing Android-side function automation for more than 2 years. The function automation frameworks I have used include Robotium, Uiautomator, and Appium. Recently, I have studied the scheme of automation case reuse, investigated the automation framework of Appium, and applied it to the standard version of Bank One Account. This article introduces the practical experience of Android function automation based on Appium in detail. It mainly includes the following aspects:

  • Appium framework principle introduction
  • Appium framework common API introduction
  • Building an automated development environment based on the Appium framework
  • Automated case development and hierarchical structure design
  • Automated test case writing specifications and precautions
  • Function automation access to continuous integration solution

Android common function automation framework comparison

The following table gives a comparison of the three frameworks Robotium, Uiautomator, and Appium.
It is particularly important to understand the characteristics of each automation framework and combine the characteristics of the product itself to select a suitable framework.


Paste_Image.png

Appium framework principle introduction

Appium is an open source, cross-platform automated testing tool for testing native and lightweight mobile applications, supporting iOS, Android and FirefoxOS platforms. Appium drives Apple's UIAutomation library and Android's UiAutomator framework, using Selenium's WebDriver JSON protocol. The following figure is the schematic diagram of Appium on the Android side


Paste_Image.png


As can be seen from the figure, Appium Client is an extension and encapsulation of webdriver's native api. It is used in conjunction with native webdriver, and both are indispensable. Appium Server has two main functions: First, it acts as an http server and receives commands sent from Appium Client (which can be considered as specific operations in the case). Secondly, as a bootstrap client, after receiving the client's commands, it sends these commands to the bootstrap of the target android machine through socket to drive Uiautomator to perform automated operations. Regarding the working principle of Appium, there is a lot of information on the Internet, and I will not introduce it in detail. You can refer to the following links
http://www.2cto.com/kf/201410/347851.html
http://www.blogjava.net/qileilove/archive/ 2014/12/23/421659.html

Appium framework common API introduction

Appium's API is included in Appium Client. The following table shows the client download address corresponding to different language platforms.


Paste_Image.png

The following table shows the common APIs of the Java platform. Other APIs can be found on Baidu or by viewing the Client source code.


Paste_Image.png


The APIs for positioning and operating Appium elements are separated, which is different from the robotium framework, and is similar to EarlGrey, Google's new iOS-side functional automation framework. Note about the api for element positioning: when the element is successfully located, the WebElement object is returned, but if the element cannot be located, this api directly reports an error instead of returning NULL. This is often error-prone for common operations such as "judging whether a control exists", such as using the following code to judge whether the login button exists.

public boolean isLoginButtonShow(){
  WebElement wl = DriverManager.getInstance().findElementById(packagename
                    +  ":id/login_input_account");
  return wl.isDisplayed();
 }

When the login button exists, it returns true, but if the login button does not exist, the above code does not return false, but crashes directly on line 2. Exceptions can be caught by try catch, modified as follows:

public boolean isLoginButtonShow(){
    try{
    WebElement wl = DriverManager.getInstance().findElementById(packagename  
                +  ":id/login_input_account");
         return wl.isDisplayed();
  }catch (Exception e){
  return false;
   }
  }

Building an automated development environment based on the Appium framework

The beginning of everything is difficult, and the establishment of an automated development environment will be more troublesome. The following explains in detail how to build an automated development environment based on Appium under the mac os operating system.
1. To build the Android development environment (JDK/SDK/AndroidStudio), please use Baidu. The required installation package can be downloaded from the following webpage:
http://tools.android-studio.org
Appium for mac installation can refer to the following link:
http: //www.cnblogs.com/oscarxie/p/3894559.html
For appium installation, it is recommended to use dmg installation, click to download the installation package. The "npm install -g appium" command line installation pro test keeps reporting errors.
2. Create a new android project AppDemo in AndroidStudio.
3. Create a java module (appium): new—>new module—>java library, this java project is used to develop automation cases. 4. Install Appium
Client: create a java module (selenium), import the relevant selenium package in the libs directory, click to download the selenium compressed package
.
6. In the appium module, create a new java class and start developing automated cases. So far, the AppDemo project directory structure is as follows:


Paste_Image.png

7、启动appium server(命令行或者图形界面启动),注意,启动时Android Settings中请勾选No Reset选项,可防止每次执行case时,都重新安装app,如下所示。


Paste_Image.png


8、case执行,可通过IDE和脚本两种方式执行case
IDE方式:case名右击—>run
脚本方式:auto_run.sh,见下方

#!/bin/bash
#auto_run.sh
source ~/.bash_profile
cd ./AppDemo
gradle clean
gradle build
export CLASSPATH=$APPIUM_HOME/java-client-3.3.0.jar:$APPIUM_HOME/selenium-java-2.48.2-srcs.jar:$APPIUM_HOME/selenium-java-2.48.2.jar:$APPIUM_HOME/junit-4.12.jar:$APPIUM_HOME/hamcrest-core-1.3.jar:$APPIUM_HOME/libs/*  
cd ./appium
java -classpath $CLASSPATH:./build/libs/appium.jar  org.junit.runner.JUnitCore   com.incito.appiumdemo.cases.PersonalCente

其中CLASSPATH需要设置为Appium Client所在路径,
com.incito.appiumdemo.cases.PersonalCenter为case所在类,脚本的执行方式有利于自动化接入持续集成和平台化。
至此基于Appium的自动化开发环境搭建完成,下一节介绍如何开发自动化case及case的分层结构设计。

基于Appium的自动化case开发及case分层结构设计

首先为每条case创建一个公共的基类AppiumTestBase,内含setup和teardown两个方法,以后每条case继承该基类即可。代码如下:

public class AppiumTestBase {    
  public WebDriverWait webwait;    
private AndroidDriver driver;    
@Before    
public void setUp() throws Exception {        
File classpathRoot = new File(System.getProperty("user.dir"));        
File appDir = new File(classpathRoot, "apps");        
File app = new File(appDir, Config.CURRENT_BANK);        
DesiredCapabilities capabilities = new DesiredCapabilities();        capabilities.setCapability("deviceName",Config.DEVICE_NAME);        capabilities.setCapability(CapabilityType.BROWSER_NAME, "");        capabilities.setCapability(CapabilityType.VERSION, "5.0.1");        capabilities.setCapability("platformName", "android");        
capabilities.setCapability("app", app.getAbsolutePath());        
capabilities.setCapability("udid", Config.DEVICE_NAME);//adb devices获得的值        
driver = new AndroidDriver(new URL("http://127.0.0.1:"+Config.APPIUM_PORT+"/wd/hub"), capabilities);        
webwait = new WebDriverWait(driver,10);        
DriverManager.init(driver);        
DriverManager.initWebWait(webwait);        
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);    
}    
@After    
public void tearDown() throws Exception {        
driver.quit();    
}

setup操作包含导入待测应用apk包,设置与Appium Server连接所需参数,并初始化AndroidDriver对象。以标版登录case为例,其需要继承AppiumTestBase,代码如下:

package com.incito.appiumdemo;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import io.appium.java_client.android.AndroidDriver;
public class AccountLogin extends AppiumTestBase{    
/**     
* case 编号 AccountLogin_001     
* ****@throws ****Exception     
*/    
@Test    
public void testAccountLogin() throws Exception {        
Account.*getInstance*().gotoLoginPage();        
Account.*getInstance*().doLogin();    
}
/**     
* case 编号 AccountLogin_002     
* ****@throws ****Exception     
*/   
@Test    
public void testLoginout() throws Exception {        
Account.*getInstance*().gotoGestureLoginPage();        
Account.*getInstance*().doGestureLogin(Config.*CURRENT_USERNAME*);        
Personal.*getInstance*().doLogout();    
}

testAccountLogin Case中,执行了两步操作:进入登录页面;执行登录操作。这两步操作都封装在Account类里面。由此引入自动化case的分层设计框架,如下图:


Paste_Image.png

自动化开发过程中,经常遇到的一个问题是,随着产品的不断更新迭代,APP的UI会不断发生变化,自动化如何去应对这样的变化,如何降低其维护代价。case分层设计主要是基于自动化可维护性的考虑,可维护性是功能自动化最重要的评价指标之一,其直接决定了自动化是否能开展下去。试想case数量达到一定程度时,若没有采用封装、分层的设计思路,极有可能出现“牵一发而动全身”的问题。下图是标版自动化case的分层目录图。


Paste_Image.png


下面以登录case为例,详细了解其分层调用关系。登录case在cases层的AccountLogin类中,其代码上面已经展示,回到testAccountLogin Case的操作,第二步操作为Account.getInstance().doLogin();即在登录页面执行登录操作,其封装在business层的Account类中,代码片段如下:

public void doLogin(){    
LoginUiAction.*getInstance*().enterUsername(Config.*CURRENT_USERNAME*);    LoginUiAction.*getInstance*().enterPassword(Config.*CURRENT_PASSWORD*);    LoginUiAction.*getInstance*().clickLogin();    
HomeUiAction.*getInstance*().clickOnCancelGesture();    
Assert.*assertTrue*(LoginUiAction.*getInstance*().isLogin());
}

doLogin()方法中执行了“输入用户名;输入密码;点击登录按钮;判断登录是否成功”操作,显然这几步操作都在UI层LoginUiAction类中。我们再查LoginUiAction.getInstance().
enterUsername()方法中做了什么,代码片段如下:

//输入用户名
public void enterUsername(String username){    
WebElement wl = DriverManager.*getInstance*().findElementById(packagename +    
      ":id/login_input_account");    
 wl.clear();   
 wl.sendKeys(username);
}

enterUsername()方法中,先根据id定位用户名输入框,然后清空输入框,再输入用户名,这些操作都是Appium Client中提供的API。至此演示了登录case的分层调用过程:cases—>business—>ui—>api。按照分层结构,只要业务逻辑不变,case维护任务主要放在ui层,上层无需改动,如此可极大减少case的维护代价。
在doLogin()方法中有一个“判断登录是否成功”的操作,断言操作是自动化测试用例中必不可少的一部分,下面就开始介绍自动化测试用例的书写规范。

自动化测试用例书写规范及注意事项

一条case一般需要包括如下几个要素:

  • 数据准备
  • 具体操作
  • 验证点
  • 清楚操作结果

数据准备指提前准备测试账号,假数据等;具体操作得按照业务测试同学提供的文本case来转化;验证点指自动化操作后,UI前后的变化点,比如登录后,首页会出现用户名、总资产、财富分等控件,这些都是验证点;清楚操作结果主要是基于case独立性的考虑,尽可能做到每条case是独立的,这样某条case fail了,也不会对其他case造成影响,当然这样会增加case的粒度,case稳定性会受影响,两者之间可自行平衡。
下面介绍case开发的注意事项:

  1. 元素定位
    • ID(首选)
    • 文本
    • 控件类型
    • 坐标
  2. UI操作需要合理的sleep
  3. case独立性
  4. 封装常用操作
  5. 注释及case前写明操作步骤

元素定位有ID/文本/控件类型/坐标四种方式,推荐使用ID,因为只要某个控件还存在,其ID变化的可能性很小,若其位置发生了变动,case都无需维护。
下面给出查找元素ID的几种方法:uiautomatorviewer/hierarchyviewer/源码。uiautomatorviewer和hierarchyviewer工具在Android SDK中,配置好环境变量后,直接在命令行输入命令即可打开图形化工具,hierarchyviewer需要手机root,推荐使用uiautomatorviewer。如果有待测应用的源码,也可以通过源码来找ID,当然这种方式比较痛苦,但对熟悉业务及个人成长是有好处的,我最开始就是通过源码来找ID的。
对于一些奇葩的情况,元素ID/文本/控件类型都无法定位时,使用坐标定位绝对好使,但不到万不得已,尽量不用,因为用坐标定位就失去了兼容性,换个手机,case可能会执行失败。
UI操作需要合理的sleep,经常由于网络原因,UI加载需要一定时间,自动化操作过程中需要合理的sleep,sleep时间短了,case会失败,长了又浪费时间。Appium框架中引入了隐式sleep方案,在初始化代码中添加driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);即可,表示每步操作最多等待10s。
case独立性前面已介绍,封装及注释容易理解,不做过多解释。

功能自动化接入持续集成方案

功能自动化一般用于项目集中测试、回归测试、dailybuild等,我们不可能通过IDE手动来运行case,一般可借助于jenkins或平台化的方式来批量执行case。下面介绍如何将功能自动化接入jenkins。


Paste_Image.png


接入jenkins主要用到了其定时和轮询的功能,我们只要准备好构建jar(build.sh)和执行case(execCase.sh)的脚本,放入jenkins的Excute shell模块,然后配置定时或轮询的时间即可。build.sh和execCase.sh可参照第四部分介绍的auto_run.sh。具体执行过程如上图所示:jenkins触发自动化job;拉取构建站最新apk,拷贝至appium module的apps目录下;构建测试工程,生成appium.jar(build.sh);批量执行case(execCase.sh),最后jenkins会输出自动化的执行结果,但是输出结果可视化程度不好,可自行开发生成报告脚本。至此详细介绍了基于Appium的功能自动化开发全过程。

 

原文链接:http://www.51test.space/archives/2006

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326174140&siteId=291194637