android的自动化测试方案,弄了好久了。

Google在sdk4.0以后提供了一个自动化解决方案uiautomator:

优点:可以跨应用了;这可是亲生的;

缺点:必须sdk4.0以上版本;要想实现的好,最好有开发配合;java项目编译为jar后需要push到手机才能运行,也就是说必须打印日志暴力调试。

后来听到群友Teddy说到appium和calabash-android,翻了一下appium的文章,发现:

01.jpg

手把手教你uiautomator_android自动化测试第一个示例_UIautomator

Appium基于Android InstrumentationFramework和UIAutomator,也就是说这个工具是可以跨应用的。说远了,好吧,为了帮大家更容易理解appium的使用,我这里就讲一下uiautomator的使用方法。

首先提供uiautomator的官方网页:

http://developer.android.com/tools/help/uiautomator/index.html

你应该有android-sdk吧,升级到4.0以上,进入目录android-sdk\tools,你会看到两个文件:

traceview.bat 和 uiautomatorviewer.bat,这俩文件让你想起了monkeyrunner了吧,是的,traceview.bat就对应于hierarchyviewer.bat,用来查看程序的ui界面的,通常也是使用管理员权限启动的。

好了,现在用eclipse创建一个java project,是的,你没看错,是java project不是android project,添加引用:

02.jpg

手把手教你uiautomator_android自动化测试第一个示例_UIautomator_02

在project.properties中内容为:

# Project target.

target= android-16

这里的android-16需要和之前的android.jar和uiautomator.jar位置相一致。

然后呢?写代码吧,建立一个类,得,发个给大家参考:

package com.uia.example.my;

import org.apache.http.util.EncodingUtils ;

import android.graphics.Bitmap ;

import android.graphics.BitmapFactory ;

import android.graphics.Rect ;

import android.os.Environment;

import com.android.uiautomator.core.UiObject;

import com.android.uiautomator.core.UiObjectNotFoundException;

import com.android.uiautomator.core.UiScrollable;

import com.android.uiautomator.core. UiSelector ;

import com.android.uiautomator.testrunner.UiAutomatorTestCase;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

public class TAppWorkAssistV1  extends UiAutomatorTestCase {  

public String sLog ;

public File fout = null ;

public FileOutputStream outStream = null ;

public void write2file(String filename,String sData)

     {

          String sLog= "" ;

          // 初始化日志文件

if (Environment. getExternalStorageState ().equals(Environment.MEDIA_MOUNTED )){

          sLog = Environment. getExternalStorageDirectory ().getAbsolutePath();


try {

                fout = new File(sLog,filename);

                outStream = new FileOutputStream( fout , true );   // 此处的 true 是append

                sData=sData + "\n" ;

                outStream .write(sData.getBytes());

                outStream .flush();

                outStream .close();

                fout = null ;

           }

catch (Exception e){

                e.printStackTrace();

           }

       } else {

          System. out .println( " 该手机没有 SD 卡 " );

       }

     }

public void testDemo() throws UiObjectNotFoundException {

             //1. 启动 app

             getUiDevice().pressHome();

             UiObject allAppsButton = new UiObject( new UiSelector().description("Apps" ));

             allAppsButton.clickAndWaitForNewWindow();


             UiObject appsTab = new UiObject( new UiSelector().text( "Apps" ));

             appsTab.click();

             UiScrollable appViews = new UiScrollable( new UiSelector().scrollable(true ));


             UiObject settingsApp = appViews.getChildByText( newUiSelector().className(android.widget.TextView. class .getName()), "Efilm" );

             settingsApp.clickAndWaitForNewWindow();


             //2. 进入主界面

             System. out .println( "into main view" );

             System. out .println(getUiDevice().waitForWindowUpdate("com.eshore.efilm" , 60000));

             System. out .println( "intoed main view" );

             UiObject tv1 = new UiObject( new UiSelector().text( " 影院 " ));

             tv1.click();


             //3. 点击影院

             UiObject oyy= new UiObject( new UiSelector().description( "cinema_row"));

             System. out .println( "wait yingyuan come out" );

             oyy.waitForExists(60000);

             System. out .println( "yingyuan come out" );

             oyy.clickAndWaitForNewWindow();

             System. out .println( "click yingyuan" );


             //4. 场次

             UiObject occ= new UiObject( new UiSelector().description("LinearLayout10" ));

             System. out .println( "wait changci come out" );

             oyy.waitForExists(60000);

             System. out .println( "changci come out" );

             occ.clickAndWaitForNewWindow();

             System. out .println( "click changci" );

             //5. 座位

             UiObject oseat= new UiObject( new UiSelector().description("cinema_shows_list_item" ).index(0).childSelector( new UiSelector().description("LinearLayout10" )));

             System. out .println( "wait seat come out" );

             oseat.waitForExists(5000);

int h=getUiDevice().getDisplayHeight();

int w=getUiDevice().getDisplayWidth();

             System. out .println( "(h/2,w/2)=" +h/2+ "," +w/2);

             getUiDevice().click(h/2,w/2);

             //System.out.println("seat count:"+String.valueOf(oseat.getChildCount()));

             //System.out.println("seat getText:"+ oseat.getText());


             // 截座位图

             Process process;

try {

                   process = Runtime. getRuntime ().exec( "screencap /mnt/sdcard/EfilmFailSnapShot01.png" );

try {

                        process.waitFor();

                   } catch (InterruptedException e) {                   // TODO Auto-generated catch block

                        e.printStackTrace();

                   }

             } catch (IOException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

             }

             //takeScreenShots("EfilmSeatSnapShot");

     }

}

这个例子是随便写的,可能不够严谨。大体就这么个情况吧。下一步就是编译执行了,先插上手机usb接口,然后打开cmd,执行:

找到SDKID,也就是android create中的-t参数:

cd C:\ PROGRAM\android-sdk\tools

android list

找到t参数的值以后:

cd C:\ PROGRAM\android-sdk\tools

android create uitest-project -n TAppWorkAssistV1 -t 25 -p C:\android自动化\Tv2.0\TestSetting

cd C:\android自动化\Tv2.0\TestSetting

ant build

cd C:\android自动化\Tv2.0\TestSetting\bin

adb push TAppWorkAssistV1.jar /data/local/tmp/

adb shell uiautomator runtest TAppWorkAssistV1.jar -c com.uia.example.my. TAppWorkAssistV1

看了看,好像没有什么特别值得解释的

-n TAppWorkAssistV1:类名

-p: 项目所在目录

Ant build 把这个类编译成一个jar包:TAppWorkAssistV1.jar

然后把jar包push到手机上,调用执行这个类就可以了

大致是这么个步骤,不过有一个非常重要的细节,就是如果你需要更省心,就最好把界面元素,无论动态的还是布局文件中的,都加上content-description属性,并保证唯一性,根据:

UiSelector:description(String desc)

Set the search criteria to match thecontent-description property for a widget.

那就可以统一只使用这一个引用界面元素的方法就行了,就不用去想方设法利用其它的属性来引用了。

如果你没有源码,那就只能根据那个traceview.bat工具来找不同的引用方法了,如果有源码,可以参考下文:

http://blog.csdn.net/testingba/article/details/19398445

说回来了,appium还有instrument部分,可以参考下文:

http://blog.csdn.net/testingba/article/details/8565533

或者参考ranorex的instrument代码,就可以理解instrument是怎么回事了,说穿了加上个instrument的jar包引用,然后设hook。

http://blog.csdn.net/testingba/article/details/19538749

有了这几部分知识做底,appium如何实现就会比较容易理解了。

如有错漏,不吝赐教。