android的自动化测试方案,弄了好久了。
Google在sdk4.0以后提供了一个自动化解决方案uiautomator:
优点:可以跨应用了;这可是亲生的;
缺点:必须sdk4.0以上版本;要想实现的好,最好有开发配合;java项目编译为jar后需要push到手机才能运行,也就是说必须打印日志暴力调试。
后来听到群友Teddy说到appium和calabash-android,翻了一下appium的文章,发现:
01.jpg
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
在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如何实现就会比较容易理解了。
如有错漏,不吝赐教。