Android自动化测试生成单元测试结果报告

转自:http://blog.csdn.net/hunterno4/article/details/14485663


使用robotium进行Android应用进行自动化测试,之前用TMTS框架,但收集到的单元测试结果常常会少掉一些用例集。。穷则思变,Android的测试框架主要是通过InstrumentationTestRunner对被测应用进行控制与执行,因此可以对InstrumentationTestRunner进行扩展以完成测试结果收集,然后通过jenkins的Publish JUnit test result report插件得到结果报告。

1.新建一个java package,新建一个java类

源码来自开源项目:https://code.google.com/p/nbandroid-utils/

源码中生成的TEST-all.xml结果文件位于/data/data/com.example/files目录下,要导出结果文件的话,需要手机拥有root权限,比较麻烦,因此下面修改了文件存放路径,有SD卡则文件位于SD卡的/robotium目录下

[java]  view plain copy
  1. package com.example.test.instrumentation;  
  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(nullnull);  
  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('\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.     @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. }  

2.修改AndroidManifest.xml文件

将原来的:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <instrumentation  
  2.         android:name="android.test.InstrumentationTestRunner"  
  3.         android:targetPackage="com.example" />  
修改为:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <instrumentation  
  2.         android:name="com.example.test.instrumentation.InstrumentationTestRunner"  
  3.         android:targetPackage="com.example" />  


3.修改Run Configurations
右键测试工程>Run as >Run Configurations
在Test栏中,勾选Run all tests in the selected project,or package
这样每次在Eclipse中运行时才会使用新的InstrumentationTestRunner
在Instrumentation runner处下拉选择新写的InstrumentationTestRunner
点击Apply完成设置

4.命令行下运行测试用例

Running all tests: adb shell am instrument -w com.android.foo/com.example.test.instrumentation.InstrumentationTestRunner

Running a single testcase: adb shell am instrument -w -e class com.android.foo.FooTest com.android.foo/com.example.test.instrumentation.InstrumentationTestRunner 

Running multiple tests: adb shell am instrument -w -e class com.android.foo.FooTest,com.android.foo.TooTest com.android.foo/com.example.test.instrumentation.InstrumentationTestRunner 

命令行下运行测试用例与平时一样,只要将原来的InstrumentationTestRunner换成新的InstrumentationTestRunner就行,

需要注意的是,由于每次命令行执行完毕,都会覆盖原有的TEST-all.xml文件,即如果采用Running a single testcase方式运行多个测试用例集,则最后结果只会记录最后一个用例集。

因此可以使用传参数的形式分别命名输出的文件名

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private static final String OUT_FILE_ARG = "outfile";  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public void onCreate(Bundle arguments) {  
  3. if ( arguments != null ) {  
  4. mOutFileName = arguments.getString(OUT_FILE_ARG);  
  5. }  
  6. if ( mOutFileName == null ) {  
  7. mOutFileName = OUT_FILE_DEFAULT;  
  8. }  
  9. super.onCreate(arguments);  
  10. }  

此时运行命令换为adb shell am instrument -w -e outfile "TEST-***.xml" -e class com.android.foo.FooTest,com.android.foo.TooTest com.android.foo/com.example.test.instrumentation.InstrumentationTestRunner


5.运行完成后将手机中的文件导出
adb -s $ANDROID_AVD_DEVICE pull /mnt/sdcard/rototium/TEST-all.xml

其中$ANDROID_AVD_DEVICE为参数化的手机序列号


6.在jenkins中任务构建完成后即可使用Publish JUnit test result report插件分析得出单元测试报告了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值