首页 > 代码库 > robotium脚本封装为APK,实现脱离手机数据线,使用按钮点击控制用例运行的小功能

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     @Override100     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(‘\n‘));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     @Override165     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签名,然后......安装到你的手机上,拔掉该死的数据线,点击按钮,开始自动虐你的手机吧:)