看过很多博客,对于UIAutomator2.0的讲解,多是从API方面进行理论叙述,个人感觉不好理解,实战性差。因此,想从实战应用的角度,记录UIAutomator2.0的使用。本文为开篇,希望起个好头。
UIAutomator是android的自动化测试框架,可跨APP。与instrumentation框架不同,UIAutomator不需要测试对象源码,因此,为黑盒测试框架。同时,与Monkey不同,UIAutomator不以坐标为主线,而是通过控件属性过滤(比如搜索文本为“提交”的按钮),获取控件本身。这很像小时候玩红白机游戏所用的金手指软件。
Android SDK提供了UIAutomatorView工具,用于获取APP的布局信息,间接辅助测试。关于工具的使用,可以参照之前的博文http://m.blog.csdn.net/daihuimaozideren/article/details/78226810,这里就不再叙述。
说一句“欲练此功必先自宫”的话,省得部分同学浪费时间。
UIAutomator的缺点,是只支持SDK 16(Android 4.1)及以上,不支持Hybird App、WebApp。
关于UIAutomator的官方文档,可参照https://developer.android.google.cn/reference/android/support/test/uiautomator/package-summary.html
网上很多教程都是关于1.0版本的,而2.0版本从表象上,可以看做是在API上进行的丰富(例如APP的启动方式),以及缺陷的修补(例如不支持中文)。若未接触过1.0,可以直接忽略。
两者的主要区别如下
(a)2.0基于 Instrumentation, 可以获取应用Context,可以使用Android服务及接口。
(b)2.0基于 Junit4,测试用例无需继承于任何父类,方法名不限,使用Annotation进行, 1.0需要继承UiAutomatorTestCase,测试方法需要以test开头。
(c)2.0采用Gradle进行构建,1.0使用Maven或Ant。
(d)2.0新增UiObject2、Until、By、BySelector等接口。
(e)2.0输出到Logcat,1.0可以使用System.out.print输出流回显至执行端。
(f)2.0输出为APK,1.0输出为JAR。
简单来讲,2.0操作更方便了。
忘记前面的啰嗦,我们使用Android Studio创建一个UIAutomator2.0的工程。
而过程,只需要两步。
(a)创建一个简单的Android工程(有无Activity无所谓)。
(b)在对应module的build.gradle文件中,添加对uiautomator的dependends引用
compile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
需要注意的是minSdkVersion必须大于等于18。
IDE在创建工程时,为我们同时创建了测试样例ExampleInstrumentedTest。
Android通过Annotation来识别测试用例
(a)红色:通过声明@RunWith(AndroidJUnit4.class),来表示该类为一个测试集合。
(b)黄色:通过声明@Test,来表示该方法为一个测试用例。
(c)蓝色:“快进箭头”,用于运行一组测试用例。
(d)绿色:“播放箭头”,用于运行一个测试用例。
点击“快进箭头”或“播放箭头”,将提供不同的运行方式
所以,如果我们要创建一个测试集合,只需要遵循(a)(b)即可。
当然,还有很多声明方式,我们将用单独的篇幅进行讲解。
手头有一个未完成的Calculator APP,我们用来作为测试对象,实现以下两个最简单测试操作。
(a)打开APP
(b)关闭APP
那么,我们需要做哪些准备?
(a)获取packageName
(b)获取设备用例
(c)判断设备状态
(d)操作APP
对于packageName的获取,UIautomatorView可以帮忙。如果需要知道launchActivity的话,可以使用SDK自带工具aapt,具体步骤这里不再描述,毕竟本文的样例中,未用到launchActivity。
对于launchActivity感兴趣的同学,可以参照http://blog.csdn.net/daihuimaozideren/article/details/78267642
下面我们来编写测试样例。
(a)创建SalaryShowAppTest类,并声明@RunWith(AndroidJUnit4.class)
(b)创建TestCase1方法,并声明@Test
SalaryShowAppTest类源码如下
public class SalaryShowAppTest {
private final String TAG=getClass().getName();
private String mPackageName="com.breakloop.salaryshow";
@Test
public void case1(){
UiDevice mDevice=UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());//获取设备用例
try {
if(!mDevice.isScreenOn()){
mDevice.wakeUp();//唤醒屏幕
}
} catch (RemoteException e) {
e.printStackTrace();
}
//mDevice.pressHome(); //按home键
startAPP(mPackageName); //启动app
mDevice.waitForWindowUpdate(mPackageName, 5 * 2000);//等待app
closeAPP(mDevice,mPackageName);//关闭app
}
private void startAPP(String sPackageName){
Context mContext = InstrumentationRegistry.getContext();
Intent myIntent = mContext.getPackageManager().getLaunchIntentForPackage(sPackageName); //通过Intent启动app
mContext.startActivity(myIntent);
}
private void closeAPP(UiDevice uiDevice,String sPackageName){
Log.i(TAG, "closeAPP: ");
try {
uiDevice.executeShellCommand("am force-stop "+sPackageName);//通过命令行关闭app
} catch (IOException e) {
e.printStackTrace();
}
}
private void startAPP(UiDevice uiDevice,String sPackageName, String sLaunchActivity){
try {
uiDevice.executeShellCommand("am start -n "+sPackageName+"/"+sLaunchActivity);//通过命令行启动app
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行效果图如下:
样例中,提供了两种APP启动方式,一种为Intent方式(无需知道LaunchActivityName),一种为命令行方式。
这里仍存有疑问,尚未解决。如果有知道的同学,还望指点。
若在打开APP之前,调用UIDevice的pressHome()方法,将会影响APP的关闭。现象为APP未关闭,且APP开启时有延时。测试机器为华为Mate8,Android7.0版本。