1. 程式人生 > >自動化測試中級篇——LazyAndroid UI自動化測試框架使用指南

自動化測試中級篇——LazyAndroid UI自動化測試框架使用指南

簡介

       一直以來,安卓UI自動化測試都存在以下兩個障礙,一是測試工具Mokey/Appium等的學習成本較高,不方便剛接觸移動端自動化的新手入門;另一個是,在測試程式碼書寫中耗費在控制元件元素查詢上的時間太多,在一些稍微複雜的應用中尤其突出。LazyAndroid正是為了解決這些問題而誕生的一款UI自動化測試框架。它基於appium,封裝了appiumDriver的設定、安卓基本控制元件的使用和手機的滑動、按鍵等基本操作,增加了元素查詢的重試機制、異常處理截圖等。結合LazyUiautomaterViewer工具自動生成的bean層java程式碼,更可以使QA可以無需親自動手完成具體頁面中控制元件的抓取,無需關心appium api的使用,即可輕鬆完成測試邏輯程式碼的書寫。

使用方法

二.建立測試工程,引入上面的jar包,開始測試程式碼的書寫。下面以測試京東錢包apk的登陸和轉賬功能為例,以Maven作為專案管理工具,結合LazyUiAutomaterViewer工具進行示範(LazyAndroid也可以不依賴LazyUiAutomaterViewer單獨使用)。

建立maven測試工程(前提是已下載安裝maven和IDE的maven外掛),在pom檔案中新增jar包依賴(jar包已推到我們公司maven私服)。

Pom檔案如下:

<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>LazyAndroidTestDemo</groupId>

    <artifactId>LazyAndroidTestDemo</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <build>

                  <sourceDirectory>src</sourceDirectory>

                  <plugins>

                                <plugin>

                                              <artifactId>maven-compiler-plugin</artifactId>

                                              <version>3.1</version>

                                              <configuration>

                                                            <source>1.7</source>

                                                            <target>1.7</target>

                                              </configuration>

                                </plugin>

                  </plugins>

    </build>

    <dependencies>

                  <dependency>

                                <groupId>org.testng</groupId>

                                <artifactId>testng</artifactId>

                                <version>6.9.9</version>

                  </dependency>

                  <dependency>

                                <groupId>org.slf4j</groupId>

                                <artifactId>slf4j-log4j12</artifactId>

                                <version>1.7.2</version>

                  </dependency>

                  <dependency>

                                <groupId>lazyAndroid</groupId>

                                <artifactId>lazyAndroid</artifactId>

                                <version>0.0.1-SNAPSHOT</version>

                  </dependency>

    </dependencies>

</project>

三.抓取頁面元素匯出java檔案。

手機使用USB線連上電腦,啟動LazyUiAutomaterViewer,進行截圖和抓取。LazyUiAutomaterViewer工具的獲取及使用方法參見《LazyUiAutomatorViewer使用說明》

四.開始測試程式碼的書寫:

  • 匯入Bean層程式碼。將LazyUiAutomaterViewer自動生成的java程式碼匯入到專案bean層中。

下面是京東錢包登入頁使用LazyUiAutomaterViewer自動抓取、匯出的java檔案:

package test.java.bean;

import lazy.android.annotations.*;

import lazy.android.bean.BaseBean;

import lazy.android.controls.*;

import io.appium.java_client.AppiumDriver;

/**

 * Gennerated by lazyUiautomaterViewer.

 */

public classLoginBean extendsBaseBean{

   @Xpath(xpath={"//android.widget.TextView[@resource-id='com.wangyin.payment:id/txt_main_title']"})

   @Description(description="登入")

   public  PlainText textView1;

  @Xpath(xpath={"//android.view.View[@resource-id='com.wangyin.payment:id/view_divider_line']"})

   @Description(description="")

   public  View view1;

   @Xpath(xpath={"//android.widget.ScrollView[@resource-id='com.wangyin.payment:id/fragment_container']"})

   @Description(description="")

   public  View scrollView2;

  @Xpath(xpath={"//android.widget.RadioGroup[@resource-id='com.wangyin.payment:id/main_footbar_menu']"})

   @Description(description="")

   public  View radioGroup3;

   @Xpath(xpath={"//android.widget.RadioButton[@resource-id='com.wangyin.payment:id/login_tab_phone']"})

   @Description(description="錢包賬戶")

   public  Click jdpayAccount;

   @Xpath(xpath={"//android.widget.RadioButton[@resource-id='com.wangyin.payment:id/login_tab_jd']"})

   @Description(description="京東賬戶")

   public  Click jdAccount;

   @Xpath(xpath={"//android.widget.LinearLayout[@resource-id='com.wangyin.payment:id/layout_login_jd']/android.view.View[1]"})

   @Description(description="")

   public  View view4;

   @Xpath(xpath={"//android.widget.EditText[@resource-id='com.wangyin.payment:id/cp_input_combox_jd']"})

   @Description(description="京東商城手機號/使用者名稱/郵箱")

   public  Text editTextUserName;

   @Xpath(xpath={"//android.widget.TextView[@text='賬號']"})

   @Description(description="賬號")

   public  PlainText textView2;

   @Xpath(xpath={"//android.widget.ImageView"})

   @Description(description="")

   public  View imageView5;

   @Xpath(xpath={"//android.widget.EditText[@resource-id='com.wangyin.payment:id/cp_input_pwd']"})

   @Description(description="")

   public  Text editJDTextPwd;

   @Xpath(xpath={"//android.widget.TextView[@text='密碼']"})

   @Description(description="密碼")

   public  PlainText textView3;

   @Xpath(xpath={"//android.widget.LinearLayout[@resource-id='com.wangyin.payment:id/layout_login_jd']/android.view.View[2]"})

   @Description(description="")

   public  View view6;

   @Xpath(xpath={"//android.widget.Button[@resource-id='com.wangyin.payment:id/btn_login_jd']"})

   @Description(description="")

   public  Click buttonLogin;

   @Xpath(xpath={"//android.widget.TextView[@resource-id='com.wangyin.payment:id/txt_jd_register']"})

   @Description(description="註冊京東賬戶")

   public  PlainText textView4;

   @Xpath(xpath={"//android.widget.TextView[@resource-id='com.wangyin.payment:id/txt_forget_pwd']"})

   @Description(description="忘記密碼?")

   public  PlainText textView5;

   @Xpath(xpath={"//android.widget.EditText[@resource-id='com.wangyin.payment:id/cp_input_combox_wy']"})

   @Description(description="請填寫手機號")

   public  Text editTextPhone;

   @Xpath(xpath={"//android.widget.TextView[@text='手機號']"})

   @Description(description="手機號")

   public  PlainText textViewPhone;

   @Xpath(xpath={"//android.widget.Button[@resource-id='com.wangyin.payment:id/btn_login']"})

   @Description(description="下一步")

   public  Click nextStep;

   @Xpath(xpath={"//android.widget.EditText[@resource-id='com.wangyin.payment:id/cp_input_pwd']"})

   @Description(description="")

   public  Text editjdPayTextPwd;

   @Xpath(xpath={"//android.widget.TextView[@text='密碼']"})

   @Description(description="密碼")

   public  PlainText textViewPwd;

   @Xpath(xpath={"//android.widget.Button[@resource-id='com.wangyin.payment:id/btn_login']"})

   @Description(description="")

   public  Click jdpayLogin;

   publicLoginBean(AppiumDriveraDriver){super(aDriver);}

}

  • page層程式碼編寫。根據測試邏輯,完成page層程式碼的書寫。基於bean層定義的控制元件變數,完成基本操作。

package test.java.page;

importorg.openqa.selenium.WebElement;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

import test.java.bean.LifeBean;

import test.java.bean.LifeBean2;

importtest.java.bean.LoginBean;

importtest.java.bean.MineBean;

importtest.java.bean.TodayBean;

importio.appium.java_client.AppiumDriver;

importlazy.android.common.LazyDriver;

public class DemoPage {

     private Loggerlogger = LoggerFactory.getLogger(this.getClass());

     private LazyDriverlazyDriver;

     private AppiumDriverdriver;

     private TodayBeantodayBean;

     private LifeBean2lifeBean2;

     private MineBeanmineBean;

     private LoginBeanloginBean;

     /**

      * 建構函式

      * @param aLazyDriver

      */

     public DemoPage(LazyDriveraLazyDriver) {

         lazyDriver = aLazyDriver;

         driver = lazyDriver.getDriver();

         todayBean = new TodayBean(driver);

         new LifeBean(driver);

         lifeBean2 = new LifeBean2(driver);

         mineBean = new MineBean(driver);

         loginBean = new LoginBean(driver);

     }

     /**

      * 登陸操作

      */

     public void login() {

         logger.info("login by jdpay account!");

         todayBean.textViewToday.expectElementExistOrNot(true);

         todayBean.textViewMine.expectElementExistOrNot(true);

         todayBean.textViewMine.click();

         lazyDriver.handleFailure("screen test:");

         mineBean.login.expectElementExistOrNot(true);

         mineBean.login.click();

         loginBean.jdpayAccount.expectElementExistOrNot(true);

         loginBean.jdpayAccount.click();

         loginBean.editTextPhone.input("13034631475");

         loginBean.nextStep.click();

         loginBean.editjdPayTextPwd.expectElementExistOrNot(true);

         loginBean.editjdPayTextPwd.input("haha123");

         loginBean.jdpayLogin.click();       

         lazyDriver.swipeToLeft();

     }

     /**

      * 轉賬操作

      * @throws InterruptedException

      */

     public void doTranAccount() throws InterruptedException {

         logger.info("transfer accounts!");

         todayBean.textViewLife.click();

         lazyDriver.swipeDown();

         lazyDriver.swipeToLeft();

         lifeBean2.textViewTransAccount.click();

         WebElement wl = lazyDriver.findElementByText("轉賬給朋友");

         wl.click();

         Thread.sleep(1000);

         lazyDriver.goBack();

         lazyDriver.goBack();

     }

}

      其中,需要注意一下建構函式。在Page層的建構函式中,需要做兩個事情。一個是給LazyDriver賦值(通過Test層傳遞過來的LazyDriver物件),另一個是通過LazyDriver物件獲取appiumDriver,來構造Bean層的類。Page層用到的所有bean層類都需要傳入appiumDriver進行構造,見下圖:

 

  • 呼叫page層方法,完成測試。

package test.java.test;

importjava.net.MalformedURLException;

importorg.testng.annotations.BeforeClass;

importorg.testng.annotations.Test;

importtest.java.page.DemoPage;

importlazy.android.common.LazyDriver;

public class DemoTest {

     private DemoPagedemoPage;

     @BeforeClass

     public void init() throws MalformedURLException {

         LazyDriver lazyDriver =new LazyDriver("jdpay.apk","com.wangyin.payment",".home.ui.MainActivity","4.2.2",false);

         demoPage = new DemoPage(lazyDriver);

     }

     /**

      * 登陸測試

      */

     @Test

     public void loginTest() {

         demoPage.login();

     }

     /**

      * 轉賬測試

      * @throws InterruptedException

      */

     @Test

     public void tranAccount() throws InterruptedException {

         demoPage.doTranAccount();

     }

}

         在test層程式碼的BeforeClass(這個demo使用了testng,但是不是必須的)中,構造了一個lazyDriver,然後通過它去構造page層的類。


            和如下appiumDriver的繁瑣設定相比較,是不是簡化很多了?

       Bean、Page和Test層是我們在測試程式碼編寫過程中,為了區分程式碼層次,根據程式碼功能定義的三個包名,不是必須的,大家可以靈活處理。

五.啟動appium, 執行或除錯測試程式碼,執行測試。