(转)robotium脚本封装为APK,实现脱离手机数据线,使用按钮点击控制用例运行

转载 2015年07月08日 11:04:31

原文:http://blog.sina.com.cn/s/blog_5b478f870102v9my.html


最近一直在完成一些robotium的小功能,用来更方便的完成一些小功能的测试,或者可以说用来娱乐吧,幸得群内大神思路指点,就此引申,终于把这个功能得以实现

---------------将robotium脚本封装为APK,使用按钮控制用例运行覆盖程度,测试结果以简单的xml文件输入到手机SD卡目录下----------------------

废话不多说,转正题:

一、首先明确一点,这篇文章,是在你所编写的robotium脚本运行无异常的前提下实施

二、阐明思路:

   1.我们需要一个运行良好的,逻辑正常的robotium工程

   2.我们需要一个可以将脚本用例运行结果保存至本地的方法

   3.我们需要一个activity,一个按钮,以及一个按钮点击事件去运行我们的robotium脚本

 

三、先介绍脚本用例运行结果的功能,我们都知道robotium用例的运行是依赖junit的Instrumentation的,所以,关于结果的输出,需要我们重写InstrumentationTestRunner类

 

package baih;

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);
        }
    }
}

 

重 写InstrumentationTestRunner类后,需要在我们的测试工程下设置run Configurations,在你的测试工程上右键-移至Run As-run Configurations-android JUnit Test,更改你工程运行的Instrumentation runner,如果不更改,默认是android.test.InstrumentationTestRunner

红色框体圈住的位置需要更改为你重写的InstrumentationTestrunner路径

完成以上步骤后,你再运行robotium脚本,就会在你的手机根目录下名为robotium的文件夹中生成一个名为TEST-ALL.xml的文件,用来记录你的脚本运行结果,结构如下:

 

运行正常的结果,会显示运行时长,运行错误的用例,会打印错误信息,至于错误信息中的中文提示,是我用例中自己加的断言,各位可以自行斟酌

 

完成这一步,就可以实施我们的封装APK计划了。封装APK,第一,我们需要一个activity

 

界面比较挫,将就看。关于activity的创建和声明,请各位自行百度

activity中可以放置一个或多个按钮,由于robotium可以使用命令行进行启动运行,所以我们可以使用不同按钮的onclick事件来执行不同的脚本

 

如上:附上各种命令行启动命令:

运行所有测试用例:

adb shell am instrument -w packagename/InstrumentationTestRunnername

运行单个测试类或某个TestSuite
adb shell am instrument -e class packagename.testclassname -w packagename/InstrumentationTestRunnername

运行某个测试类里面的某个测试方法
adb shell am instrument -e class package名.测试类名#方法名 -w 工程名.package名/InstrumentationTestRunner class名

注意:请在编写代码前,在CMD中测试你所使用的命令是否可以正常运行

完成以上步骤后,我们可以将整个测试工程打包为APK文件,记得签名需要签debug签名,然后......安装到你的手机上,拔掉该死的数据线,点击按钮,开始自动虐你的手机吧:)

号外!号外!

由于手头上一直没有android level 17及以上版本的手机,有一个shell命令启动脚本的BUG,发生在SDK level 17及以上

API>=17中加入了INTERACT_ACROSS_USERS_FULL,目的在于允许不同用户的应用之间可以产生交互,了安全,因此在交互时会校验userSerialNumber,,发现用户标识不匹配,导致权限校验失败,就会产生startInstrumentation asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL的报错,导致脚本无法调用

群里尝试,发现在17及以上版本,命令中需要加入--user 0参数

adb shell am instrument --user 0 -w packagename/InstrumentationTestRunnername

可以在调用时使用Build.VERSION.SDK_INT<17来对当前版本做判断选择合适的命令行启动方式


相关文章推荐

Android Espresso 测试框架探究

1 简介Espresso 是谷歌官方实现的一个测试框架,根据官方文档,该框架主要能实现如下的功能。 查找一个view是否显示 在一个view上触发一个动作 查询一个view中是否符合一个断言 ...

手势(由不理解drag和swipe引发的)

 drag是拖动,必须能够选中一个目标,可以是一个点。 swipe是一个滑动,可以没有目标的滑动。 而手机上的滑动解锁的小符号》或 ^ 跟手机上的图标不是一个层面上的,是无法用drag来拖拉...
  • c9316
  • c9316
  • 2016年07月14日 11:04
  • 1513

Robotium用例命令行运行、拔除数据线及TestSuite方式执行

一、命令行运行脚本及拔除数据线执行 1.所有的测试用例: adb shell am instrument -w packagename/InstrumentationTestRunnername ...

关于小米手机用AndroidStudio利用USB数据线安装APK问题

1、最近利用AndroidStudio在连接USB的小米4手机安装APK,但是失败了,一直显示一个错误, Installation failed with message Failed to est...

不使用数据线连接手机调试app 显示Log日志

不用数据线连接点手机调节app,显示LogCat信息 就跟使用数据线一样
  • Jeff169
  • Jeff169
  • 2016年05月27日 21:41
  • 718

手机如何使用USB数据线共享PC网络

手机如何使用USB数据线共享PC网络 浏览:32773|更新:2013-10-22 18:27|标签:共享  1 2 3 4 5 6 7 ...

安卓手机直读微软SQL 2000数据库 界面仿微信界面 点击按钮进入公司生产数据网站 可放大缩小左右前后滑动

我想这个东西好像没人发布过出来给大家看,就算有都是不够详细,所以我来免费发布出来,给大家参考,和烦恼怎样安卓手机开发应用读取微软SQL数据库提供参考,我这个应用可以读取SQL2000数据库、和SQL2...

脱离数据线,使用Eclipse通过WIFI调试Android程序

一、条件: 1.让电脑和手机处于同一个wifi下。 2.手机需要root 3.手机端下载远程Adb或者WIFI_ADB。 4.电脑端打开WIFI_ADB电脑端程序,点击WIFI ADB。 5.ecli...
  • itas109
  • itas109
  • 2014年02月18日 10:14
  • 2409

蒋勇软件数据线.apk

  • 2014年05月15日 21:35
  • 85KB
  • 下载

不需要数据线手机连电脑进行调试的方法(特别好用)

准备工作:  (一)root你的Android手机,没有root的话是打不开这个软件的 (二)下载app: adbWireless,并安装到手机上。 (三)找到adb工具包,sdk包里面plat...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:(转)robotium脚本封装为APK,实现脱离手机数据线,使用按钮点击控制用例运行
举报原因:
原因补充:

(最多只允许输入30个字)