zoukankan      html  css  js  c++  java
  • robotium脚本封装为APK,实现脱离手机数据线,使用按钮点击控制用例运行的小功能

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

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

    废话不多说,转正题:

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

    二、阐明思路:

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

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

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

     

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

      1 package baih;
      2 
      3 import java.io.File;
      4 import java.io.FileWriter;
      5 import java.io.IOException;
      6 import java.io.Writer;
      7 
      8 import org.xmlpull.v1.XmlPullParserFactory;
      9 import org.xmlpull.v1.XmlSerializer;
     10 
     11 import android.content.Context;
     12 import android.os.Bundle;
     13 import android.os.Environment;
     14 
     15 /**
     16  * This test runner creates a TEST-all.xml in the files directory of the application under test. The output is compatible with that of the junitreport ant task, the format
     17  * that is understood by Hudson. Currently this implementation does not implement the all aspects of the junitreport format, but enough for Hudson to parse the test results. 
     18  */
     19 public class InstrumentationTestRunner extends android.test.InstrumentationTestRunner {
     20     private Writer mWriter;
     21     private XmlSerializer mTestSuiteSerializer;
     22     private long mTestStarted;
     23     private static final String JUNIT_XML_FILE = "TEST-all.xml";
     24     
     25     
     26     @Override
     27     public void onStart() {
     28         try{
     29             File fileRobo = new File(getTestResultDir(getTargetContext()));
     30             if(!fileRobo.exists()){
     31                 fileRobo.mkdir();
     32             }
     33             if(isSDCardAvaliable()){    
     34                 File resultFile = new File(getTestResultDir(getTargetContext()),JUNIT_XML_FILE);
     35                 startJUnitOutput(new FileWriter(resultFile));
     36             }else{
     37                 startJUnitOutput(new FileWriter(new File(getTargetContext().getFilesDir(), JUNIT_XML_FILE)));
     38             }            
     39         }
     40         catch(IOException e){
     41             throw new RuntimeException(e);
     42         }
     43         super.onStart();
     44     }
     45 
     46     void startJUnitOutput(Writer writer) {
     47         try {
     48             mWriter = writer;
     49             mTestSuiteSerializer = newSerializer(mWriter);
     50             mTestSuiteSerializer.startDocument(null, null);
     51             mTestSuiteSerializer.startTag(null, "testsuites");
     52             mTestSuiteSerializer.startTag(null, "testsuite");
     53         } catch (Exception e) {
     54             throw new RuntimeException(e);
     55         }
     56     }
     57     
     58     /**
     59      * 判断SD卡是否存在
     60      * @return
     61      */
     62     private boolean isSDCardAvaliable(){
     63         return Environment.getExternalStorageState()
     64                     .equals(Environment.MEDIA_MOUNTED);    
     65     }
     66     
     67     /**
     68      * 获取测试结果报告文件所在的路径
     69      * @param context  被测工程的context
     70      * @return  返回测试结果报告文件所在的路径
     71      */
     72     private String getTestResultDir(Context context){
     73         String packageName = "/" + "robotium";
     74         String filepath = context.getCacheDir().getPath() + packageName;
     75         
     76         if(android.os.Build.VERSION.SDK_INT < 8){
     77             if(isSDCardAvaliable()){
     78                 filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+ packageName;
     79             }
     80         }else{
     81             if(isSDCardAvaliable()){
     82                 filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+ packageName;
     83             }
     84         }       
     85         return filepath;
     86     }
     87     
     88     private XmlSerializer newSerializer(Writer writer) {
     89         try {
     90             XmlPullParserFactory pf = XmlPullParserFactory.newInstance();
     91             XmlSerializer serializer = pf.newSerializer();
     92             serializer.setOutput(writer);
     93             return serializer;
     94         } catch (Exception e) {
     95             throw new RuntimeException(e);
     96         }        
     97     }
     98     
     99     @Override
    100     public void sendStatus(int resultCode, Bundle results) {
    101         super.sendStatus(resultCode, results);
    102         switch (resultCode) {
    103             case REPORT_VALUE_RESULT_ERROR:
    104             case REPORT_VALUE_RESULT_FAILURE:
    105             case REPORT_VALUE_RESULT_OK:
    106             try {
    107                 recordTestResult(resultCode, results);
    108                 } catch (IOException e) {
    109                     throw new RuntimeException(e);
    110                 }
    111                 break;
    112             case REPORT_VALUE_RESULT_START:
    113                 recordTestStart(results);
    114             default:
    115                 break;
    116         }
    117     }
    118     
    119     void recordTestStart(Bundle results) {
    120         mTestStarted = System.currentTimeMillis();
    121     }
    122 
    123     void recordTestResult(int resultCode, Bundle results) throws IOException {
    124         float time = (System.currentTimeMillis() - mTestStarted) / 1000.0f;
    125         String className = results.getString(REPORT_KEY_NAME_CLASS);
    126         String testMethod = results.getString(REPORT_KEY_NAME_TEST);
    127         String stack = results.getString(REPORT_KEY_STACK);
    128         int current = results.getInt(REPORT_KEY_NUM_CURRENT);
    129         int total = results.getInt(REPORT_KEY_NUM_TOTAL);
    130         
    131         mTestSuiteSerializer.startTag(null, "testcase");
    132         mTestSuiteSerializer.attribute(null, "classname", className);
    133         mTestSuiteSerializer.attribute(null, "name", testMethod);
    134         
    135         if (resultCode != REPORT_VALUE_RESULT_OK) {
    136             mTestSuiteSerializer.startTag(null, "failure");
    137             if (stack != null) {
    138                 String reason = stack.substring(0, stack.indexOf('
    '));
    139                 String message = "";
    140                 int index = reason.indexOf(':');
    141                 if (index > -1) {
    142                     message = reason.substring(index+1);
    143                     reason = reason.substring(0, index);
    144                 }
    145                 mTestSuiteSerializer.attribute(null, "message", message);
    146                 mTestSuiteSerializer.attribute(null, "type", reason);
    147                 mTestSuiteSerializer.text(stack);
    148             }
    149             mTestSuiteSerializer.endTag(null, "failure");
    150         } else {
    151             mTestSuiteSerializer.attribute(null, "time", String.format("%.3f", time));
    152         }
    153         mTestSuiteSerializer.endTag(null, "testcase");        
    154         if (current == total) {
    155             mTestSuiteSerializer.startTag(null, "system-out");
    156             mTestSuiteSerializer.endTag(null, "system-out");
    157             mTestSuiteSerializer.startTag(null, "system-err");
    158             mTestSuiteSerializer.endTag(null, "system-err");
    159             mTestSuiteSerializer.endTag(null, "testsuite");
    160             mTestSuiteSerializer.flush();
    161         }
    162     }
    163 
    164     @Override
    165     public void finish(int resultCode, Bundle results) {
    166         endTestSuites();
    167         super.finish(resultCode, results);
    168     }
    169 
    170     void endTestSuites() {
    171         try {
    172             mTestSuiteSerializer.endTag(null, "testsuites");
    173             mTestSuiteSerializer.endDocument();
    174             mTestSuiteSerializer.flush();
    175             mWriter.flush();
    176             mWriter.close();
    177         } catch (IOException e) {
    178             throw new RuntimeException(e);
    179         }
    180     }
    181 }

    重 写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来对当前版本做判断选择合适的命令行启动方式

  • 相关阅读:
    oracle删除用户及其名下对象
    CENTOS7设置显示中文
    hadoop安装
    linux使用flock文件锁解决crontab冲突问题
    Hive On Spark和SparkSQL
    MapReduce和Tez对比
    安装python的redis模块
    拷贝一个用户下的所有表和数据到另外一个库
    java学习笔记10--泛型总结
    java学习笔记9--内部类总结
  • 原文地址:https://www.cnblogs.com/cologne/p/3796408.html
Copyright © 2011-2022 走看看