如何在只有Apk的情况下进行测试?而且要写一个Android程序让被测试的app测试用例跑起来,然后再记录一些参数。使手机在脱离数据线的情况下尽情执行你的测试用例。没有头绪?不要着急,下面我们就来一步一步实现它。
一、准备工作
1.待测试apk文件
2.重签名工具re-sign
re-sign下载链接
3.双击打开re-sign.jar,把apk文件拖入界面,重签名成功后会显示如下界面,保存packageName和MainActivity,以便以后使用。然后把重签名后的apk安装到手机上。
4.布局查看工具Uiautomatorviewer:
一款非常好用的布局查看工具,环境配置好的前提下cmd粘贴uiautomatorviewer,回车即可打开。
二、环境搭建
推荐环境变量配置(保证re-sign.jar成功运行):
三、创建Android测试工程
a、创建Android Test Project
(1)File-New-Project-Android-Android Test Project
(2)输入工程名-next,选择This project-finish
b、创建Anroid testcase
使用uiautomatorviewer获取待测程序的布局,具体可将该工具的路径添加到环境变量中,或者进入该目录,用cmd运行,直接输入uiautomatorviewer就可以运行起来该工具,这是已经封装好的工具,可以直接用。。。
创建testcase的具体过程如下:
(1)工程名-src-包名-右击new-Junit Test Case
(2)在name一栏输入Test Case的名称
(3)Superclass一栏,选择android.test.ActivityInstrumentationTestCase2,点击finish
c、导入Robotium-jar包(需要注意和需要配置的项目)
通过建立lib文件夹,直接copy文件,需要在Build Path中进行配置。。。。具体步骤与下面添加report-jar包的步骤相同
(1)工程名-new-folder-lib
(2)直接将之前下载的robotium-solo-X.X.X.jar拷贝粘贴到lib目录下
(3)工程名-右击-Build Path-Configure Build Path-Libraries-Add External JARs
(4)点击右边的Order and Export,选择robotium-solo-X.X.X.jar的选项,点击OK
d、修改AndroidManifest.xml文件
该配置文件的修改主要包含增加节点
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="xxx.xxx.xxx" />
targetPackage与re-sign.jar中所获取到的包名相同,是指被测程序的包名
e、运行testcase
运行成功如下图所示
四、修改为测试工程
在所编写的robotium脚本运行无异常的前提下,我们需要一个activity,一个按钮,以及一个按钮点击事件去运行我们的robotium脚本。
a、重写InstrumentationTestRunner类:
先介绍脚本用例运行结果的功能,我们都知道robotium用例的运行是依赖junit的Instrumentation的,所以,关于结果的输出,需要我们重写InstrumentationTestRunner类
package mytest;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
public class InstrumentationTestRunner extends android.test.InstrumentationTestRunner {
private Writer mWriter;
private XmlSerializer mTestSuiteSerializer;
private long mTestStarted;
private static final String JUNIT_XML_FILE = "TEST-all.xml";
@Override
public void onStart() {
try{
File fileRobo = new File(getTestResultDir(getTargetContext()));
if(!fileRobo.exists()){
fileRobo.mkdir();
}
if(isSDCardAvaliable()){
File resultFile = new File(getTestResultDir(getTargetContext()),JUNIT_XML_FILE);
startJUnitOutput(new FileWriter(resultFile));
}else{
startJUnitOutput(new FileWriter(new File(getTargetContext().getFilesDir(), JUNIT_XML_FILE)));
}
}
catch(IOException e){
throw new RuntimeException(e);
}
super.onStart();
}
void startJUnitOutput(Writer writer) {
try {
mWriter = writer;
mTestSuiteSerializer = newSerializer(mWriter);
mTestSuiteSerializer.startDocument(null, null);
mTestSuiteSerializer.startTag(null, "testsuites");
mTestSuiteSerializer.startTag(null, "testsuite");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private boolean isSDCardAvaliable(){
return Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED);
}
private String getTestResultDir(Context context){
String packageName = "/" + "robotium";
String filepath = context.getCacheDir().getPath() + packageName;
if(android.os.Build.VERSION.SDK_INT < 8){
if(isSDCardAvaliable()){
filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+ packageName;
}
}else{
if(isSDCardAvaliable()){
filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+ packageName;
}
}
return filepath;
}
private XmlSerializer newSerializer(Writer writer) {
try {
XmlPullParserFactory pf = XmlPullParserFactory.newInstance();
XmlSerializer serializer = pf.newSerializer();
serializer.setOutput(writer);
return serializer;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void sendStatus(int resultCode, Bundle results) {
super.sendStatus(resultCode, results);
switch (resultCode) {
case REPORT_VALUE_RESULT_ERROR:
case REPORT_VALUE_RESULT_FAILURE:
case REPORT_VALUE_RESULT_OK:
try {
recordTestResult(resultCode, results);
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
case REPORT_VALUE_RESULT_START:
recordTestStart(results);
default:
break;
}
}
void recordTestStart(Bundle results) {
mTestStarted = System.currentTimeMillis();
}
void recordTestResult(int resultCode, Bundle results) throws IOException {
float time = (System.currentTimeMillis() - mTestStarted) / 1000.0f;
String className = results.getString(REPORT_KEY_NAME_CLASS);
String testMethod = results.getString(REPORT_KEY_NAME_TEST);
String stack = results.getString(REPORT_KEY_STACK);
int current = results.getInt(REPORT_KEY_NUM_CURRENT);
int total = results.getInt(REPORT_KEY_NUM_TOTAL);
mTestSuiteSerializer.startTag(null, "testcase");
mTestSuiteSerializer.attribute(null, "classname", className);
mTestSuiteSerializer.attribute(null, "name", testMethod);
if (resultCode != REPORT_VALUE_RESULT_OK) {
mTestSuiteSerializer.startTag(null, "failure");
if (stack != null) {
String reason = stack.substring(0, stack.indexOf('\n'));
String message = "";
int index = reason.indexOf(':');
if (index > -1) {
message = reason.substring(index+1);
reason = reason.substring(0, index);
}
mTestSuiteSerializer.attribute(null, "message", message);
mTestSuiteSerializer.attribute(null, "type", reason);
mTestSuiteSerializer.text(stack);
}
mTestSuiteSerializer.endTag(null, "failure");
} else {
mTestSuiteSerializer.attribute(null, "time", String.format("%.3f", time));
}
mTestSuiteSerializer.endTag(null, "testcase");
if (current == total) {
mTestSuiteSerializer.startTag(null, "system-out");
mTestSuiteSerializer.endTag(null, "system-out");
mTestSuiteSerializer.startTag(null, "system-err");
mTestSuiteSerializer.endTag(null, "system-err");
mTestSuiteSerializer.endTag(null, "testsuite");
mTestSuiteSerializer.flush();
}
}
@Override
public void finish(int resultCode, Bundle results) {
endTestSuites();
super.finish(resultCode, results);
}
void endTestSuites() {
try {
mTestSuiteSerializer.endTag(null, "testsuites");
mTestSuiteSerializer.endDocument();
mTestSuiteSerializer.flush();
mWriter.flush();
mWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
b、设置run Configurations
重写InstrumentationTestRunner类后,需要在我们的测试工程下设置run Configurations,在你的测试工程上右键-移至Run As-run Configurations-android JUnit Test,更改你工程运行的Instrumentation runner,如果不更改,默认是android.test.InstrumentationTestRunner
c、添加Activity
新建一个Activity作为程序入口,添加一个按钮开始测试,一个textview显示日志
六、参考
Thanks:
http://blog.csdn.net/airyzhou/article/details/38268159
http://blog.sina.com.cn/s/blog_6abda9bc01015zoc.html
http://www.cnblogs.com/keke-xiaoxiami/p/4286744.html
http://blog.sina.com.cn/s/blog_5b478f870102v9my.html
Demo下载链接