一、关于安卓自动化测试
关于测试自动化金字塔,金字塔底端是最基础的单元测试,再往上是系统接口测试,再往上就是UI自动化测试。UI自动化测试能够按照写好的用例在机器上模拟用户操作实现一系列复杂的操作过程,能够极大地解放QA的工作量,特别是在回归验证以及安卓兼容性测试方面意义较大。所以,UI自动化测试方法还是一个QA需要掌握基本的技能之一。对于安卓UI自动化测试来说,常用的框架有MonkeyRunner、Robotium、uiautomation、Appium等,其中Roboitium是较为常用的框架之一,我们就从Robotium开始学习吧。(之前用的orange框架,发现公司里基本都不用这个框架了,没人维护,于是便转向基础的Robotium框架学习,重构自动化代码)。Robotium框架可以在无需源码仅有apk的情况下进行测试。
二、Robotium自动化测试的原理
Robotium是基于instrumentation的二次封装。Roboiutm分查找控件和点击控件两大类操作。查找控件的原理是:在waitter的waitForView()方法里面通过java反射获得视图,并匹配所需要的控件,查找并返回控件对象。点击控件的原理是:查找到的控件对象解析包装成MotionEvent,基于Instrumentation框架,通过InputManager注入事件。调用类组织结构如下图简示:
三、第一个Robotium自动化工程
话不多说,开始Robotium自动化测试工程吧!
环境准备:
操作系统:windows
android SDK
IDE:eclipse+ADT插件
不需源码,只要一个apk作为被测对象。(需要打包apk时生成的R文件)这里我们用网易云阅读的apk作为被测对象。
3.1 apk重命名&安装被测应用
Robotium框架需要被测应用和测试工程需要使用相同的签名,这样才可以使用Instrumentation把被测应用启动起来。我们本机eclipse使用的签名文件可以从window-> Preferences->Android->Build中查看,一般情况下一般存放于C:\Users\yourUserName.android目录下。如下图所示:
从图中看来我的Eclipse工程使用的是C盘下的debug.keystore文件,那么需要将被测apk用此keystore文件重签名然后装到真机或者测试机上就OK了。
重签名可使用重签名工具re-sign.jar
3.2 新建Robotium自动化测试工程
1.新建工程
在Eclipse上点击File->New->Other->Android->Android Test Project,命名后点击Next,Test Target选择“This Project”,然后点Next直至Finish为止。注:可能有时候会出现Eclipse报Null Pointer Exception错误,解决方案可参考。
2.添加Robotium Jar包
右键该项目,选择property然后选择java build path, 选择 Add External JARs,选择下到的robotium-solo-5.1.jar。(注:Robotium可从网上下载Jar包)
3.新建测试用例
在项目下新建一个package,在package下新建一个测试类,该类继承自ActivityInstrumentationTestCase2。如下图简示:
注意到这里我新建了另一个package,里面只放了R.java文件,不能与测试文件放在同一个package下(会报错)。而com.pris.test这个package下新建了一个测试类FirstTestCase。FirstTestCase.java的代码如下:
package com.pris.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.robotium.solo.Solo;
import android.app.Instrumentation;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.widget.Button;
import junit.framework.Assert;
import other.R;
@SuppressWarnings("rawtypes")
public class FirstTestCase extends ActivityInstrumentationTestCase2 {
private static final String TARGET_PACKAGE_ID = "com.netease.pris";
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.netease.pris.activity.MainGridActivity";
private static Class launcherActivityClass;
private Solo solo;
static {
try {
launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
} catch (ClassNotFoundException e){
throw new RuntimeException(e);
}
}
@SuppressWarnings({ "unchecked", "deprecation" })
public FirstTestCase(){
super(TARGET_PACKAGE_ID,launcherActivityClass);
}
@Before
protected void setUp() throws Exception {
super.setUp();
/*第一套初始化方法,适用于主界面就是MainActivity的情况,只要下面一行代码就可以
this.solo = new Solo(getInstrumentation(), getActivity());*/
//第二套初始化方法,适用于主界面不是MainActivity的情况,使用Intent打开应用程序主界面
Instrumentation instrumentation = getInstrumentation();
this.solo = new Solo(instrumentation);
final String targetPackage = instrumentation.getTargetContext()
.getPackageName();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(targetPackage,
"com.netease.pris.activity.MainGridActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instrumentation.getTargetContext().startActivity(intent);
}
@Test
public void testLogin() {
boolean isOk = solo.waitForActivity("com.netease.pris.activity.MainGridActivity", 5000);
Assert.assertTrue("没有调起应用", isOk);
solo.sleep(3000);
//进入左栏账号页面
boolean isFindAccountButton = solo.waitForView(R.id.account_btn, 1, 2000);
Assert.assertTrue("没有找到账号控件", isFindAccountButton);
View account_button = solo.getView(R.id.account_btn);
solo.clickOnView(account_button);
//点击登陆按钮,打开登陆页面
boolean isLoginButton = solo.waitForView(R.id.button_login, 1, 2000);
Assert.assertTrue("没有找到登陆控件", isLoginButton);
}
@After
public void tearDown() throws Exception {
solo.finishOpenedActivities();
}
代码结构较简单,包括一些静态资源,一个构造函数,一个solo初始化方法,一个核心的测试方法,最后一个销毁solo对象的结束方法。这里需要强调的是solo初始化setUp方法。有两套初始化方法,分别适用于主界面是否就是MainActivity的情况。这里我用的网易云阅读的apk进行测试,它的MainActivity是SplashActivity(是一个广告页),没有广告或者广告播放结束后进入主界面,所以直接写solo = new Solo(instrumentation,activity)的话是无法正确创建solo对象的。需要用Intent去打开应用程序主界面。然后solo对象的话使用solo = new(instrumentation)构造方法创建。
4.修改Manifest.xml文件
主要修改的地方是instrumentation中指定TargetPackage为待测试的包名,此外检查manifest中的package是否就是本测试工程的包名。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pris.test" //这里需是本测试工程的包名
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.netease.pris" /> //这里是被测应用程序的包名
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
5.执行测试用例
在测试用例文件上右击,选择run as Android Junit Test,就可以进行测试了。运行结束,在Eclipse左右会显示运行结果。如果出错,可以去查看logcat,排查错误的原因。