第一次写blog,一直也没养成写blog的好习惯,大家将就看,先上效果图
首先参考http://blog.csdn.net/onepiece2345/article/details/8165241重写InstrumentationTestRunner 类,之所以没用android-junit-report-1.5.8.jar是因为它生成的xml只包含了错误信息,而没有正确信息,为了实现成功数、成败数、以及成功率,需要将成功信息也包含在内。
具体的存放位置按自己需要进行调整,我现在是按时间作为文件名,存在sdcard/KTTestReport下,还有输出的结点名称内容都可以根据自身需要进行相应修整,切忌拿来主义不一定适合于 你InstrumentationTestRunner 代码如下:
public class InstrumentationTestRunner3 extends android.test.InstrumentationTestRunner { private Writer mWriter; private XmlSerializer mTestSuiteSerializer; private long mTestStarted; public void onStart() { try { Date d = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-kk-mm"); String strTime = sdf.format(d); String xmlName = "Test" + strTime + ".xml"; // 如果被测的应用本身有读写sdcard权限的话级可以直接放在sdcard里面,否则机会失败, // 有测试应用源码的情况下是可以在AndroidManifest.xml里添加权限,当然所数情况下是没有源码的, // 只能放在被测应用的files目录里了,这个是不需要权限的 String SDPath = Environment.getExternalStorageDirectory() + "/"; String logPath = SDPath + "KTTestReport/"; File file = new File(logPath); if (file.exists()) { } else { file.mkdirs(); } startJUnitOutput(new FileWriter(new File(file,xmlName))); //startJUnitOutput(new FileWriter(new File(getTargetContext().getFilesDir(),xmlName))); } catch (IOException e) { throw new RuntimeException(e); } super.onStart(); } void startJUnitOutput(Writer writer) { try { this.mWriter = writer; this.mTestSuiteSerializer = newSerializer(this.mWriter); this.mTestSuiteSerializer.startDocument(null,null); this.mTestSuiteSerializer.startTag(null,"testsuites"); this.mTestSuiteSerializer.startTag(null,"testsuite"); } catch (Exception e) { throw new RuntimeException(e); } } 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); } } public void sendStatus(int resultCode,Bundle results) { super.sendStatus(resultCode,results); switch (resultCode) { case -2: case -1: case 0: try { recordTestResult(resultCode,results); } catch (IOException e) { throw new RuntimeException(e); } case 1: recordTestStart(results); } } void recordTestStart(Bundle results) { this.mTestStarted = System.currentTimeMillis(); } void recordTestResult(int resultCode,Bundle results) throws IOException { float time = (float)(System.currentTimeMillis() - this.mTestStarted) / 1000.0F; String className = results.getString("class"); String testMethod = results.getString("test"); String stack = results.getString("stack"); int current = results.getInt("current"); int total = results.getInt("numtests"); this.mTestSuiteSerializer.startTag(null,"testcase"); this.mTestSuiteSerializer.attribute(null,"ID",current + ""); this.mTestSuiteSerializer.attribute(null,"classname",className); this.mTestSuiteSerializer.attribute(null,"casename",testMethod); // Log.v("myInfor",current + ""); if (resultCode != 0) { this.mTestSuiteSerializer.attribute(null,"time",String.format("%.3f",new Object[] {Float.valueOf(time)})); this.mTestSuiteSerializer.startTag(null,"result"); 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); } this.mTestSuiteSerializer.attribute(null,"message",message); this.mTestSuiteSerializer.attribute(null,"type",reason); this.mTestSuiteSerializer.attribute(null,"reason",stack); this.mTestSuiteSerializer.text("failure"); } this.mTestSuiteSerializer.endTag(null,"result"); } else { this.mTestSuiteSerializer.attribute(null,"result"); this.mTestSuiteSerializer.attribute(null,"pass"); this.mTestSuiteSerializer.text("success"); this.mTestSuiteSerializer.endTag(null,"result"); } this.mTestSuiteSerializer.endTag(null,"testcase"); if (current == total) { // this.mTestSuiteSerializer.startTag(null,"system-out"); // this.mTestSuiteSerializer.endTag(null,"system-out"); // this.mTestSuiteSerializer.startTag(null,"system-err"); // this.mTestSuiteSerializer.endTag(null,"system-err"); this.mTestSuiteSerializer.endTag(null,"testsuite"); this.mTestSuiteSerializer.flush(); } } public void finish(int resultCode,Bundle results) { endTestSuites(); super.finish(resultCode,results); } void endTestSuites() { try { this.mTestSuiteSerializer.endTag(null,"testsuites"); this.mTestSuiteSerializer.endDocument(); this.mTestSuiteSerializer.flush(); this.mWriter.flush(); this.mWriter.close(); } catch (IOException e) { throw new RuntimeException(e); } } }
完成后需要修改AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ktplay.sample.test" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" /> <!-- report.jar使用这个<instrumentation android:name="com.zutubi.android.junitreport.JUnitReportTestRunner" android:targetPackage="被测程序包名" /> --> <instrumentation android:name="测试程序包名.InstrumentationTestRunner3" android:targetPackage="<span style="font-family: Arial,Helvetica,sans-serif;">被测程序包名</span><span style="font-family: Arial,sans-serif;">" /></span> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <uses-library android:name="android.test.runner" /> </application> </manifest>然后在run config中将
InstrumentationTestRunner3配置好,如下图
万事具备只欠运行,现在就可以让你的程序跑起来,最后会生成一个xml,可以打开看看是不是你要的信息,如果不正确可适当修改
接下来就是大家比较关心的html了,我是用dom去解析xml存到list里然后又拼接的html,方法可能有些笨,如果哪位大神有好的方法还请赐教
import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DomParseXml { static final String KTREPORT_XML_DIR = "E:\\KTtestReport\\"; public List<Report> getReports() throws Exception { List<Report> list = new ArrayList<Report>(); DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = db.parse(new File(getName(KTREPORT_XML_DIR)));// 把文件解析成DOCUMENT类型,目前先写死,最后用通配符匹配 Element element = document.getDocumentElement(); NodeList reportNodes = element.getElementsByTagName("testcase"); for (int i = 0; i < reportNodes.getLength(); i++) { Element reportElement = (Element)reportNodes.item(i); Report report = new Report(); report.setTime(Float.valueOf(reportElement.getAttribute("time"))); report.setId(Integer.parseInt(reportElement.getAttribute("ID"))); report.setClassName(reportElement.getAttribute("classname")); report.setCaseName(reportElement.getAttribute("casename")); NodeList childNodes = reportElement.getChildNodes(); int total = reportNodes.getLength(); for (int j = 0; j < childNodes.getLength(); j++) { if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) { if ("result".equals(childNodes.item(j).getNodeName())) { report.setResult(childNodes.item(j).getFirstChild().getNodeValue()); NamedNodeMap attributes = childNodes.item(j).getAttributes(); for (int m = 0; m < attributes.getLength(); m++) { Node attribute = attributes.item(m); // 得到属性名 String attributeName = attribute.getNodeName(); // 得到属性值 String attributeValue = attribute.getNodeValue(); if("message".equals(attributeName)) { report.setMessage(attributeValue); } else if("reason".equals(attributeName)) { report.setReason(attributeValue); } else if("type".equals(attributeName)) { report.setType(attributeValue); } } } } report.setTotal(total); list.add(report); } } return list; } public static String getName(String path) { List<String> nameList = new ArrayList<String>(); File file = new File(path); if (file.isDirectory()) { File[] dirFile = file.listFiles(); for (File f : dirFile) { if (f.isDirectory()) { getName(f.getAbsolutePath()); } else { if (f.getName().endsWith(".xml") ) { nameList.add(f.getAbsolutePath()); } } } } Collections.sort(nameList); if(nameList.size()<=0) { return ""; } return nameList.get(nameList.size()-1); } public static void main(String[] args) { String nameString = getName("E:\\KTtestReport\\"); System.out.println(nameString); } }
拼装
package xxx.report; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class GenerateHtmlReport { static final String KTREPORT_HTML_DIR = "E:\\report.html"; public static void generateReports() { DomParseXml dom = new DomParseXml(); List<Report> reports = new ArrayList<Report>(); int succNum = 0; int failNum = 0; float totalTime = 0.0f; try { reports = dom.getReports(); for(Report report :reports) { //System.out.println(report.getTotal()-report.getSuccessNum()); if("failure".equals(report.getResult())) { failNum++; } else { succNum++; } totalTime = totalTime+report.getTime(); } } catch (Exception e) { e.printStackTrace(); } writeToHtml(totalTime,succNum,failNum,reports); } private static void writeToHtml(float totalTime,int succNum,int failNum,List<Report> reports) { try { PrintStream out = new PrintStream(new FileOutputStream(KTREPORT_HTML_DIR)); System.setOut(out); System.out.println("<h3 align=left><font color=#0000FF>Robotium Test Report</font></h1>"); StringBuffer str = new StringBuffer(); str.append("<html>\n"); str.append("<body>\n"); str.append("<table border='1px' cellspacing='0px' width='100%' bordercolor='#000000'>"); str.append("<tr>Start Time:"); Date date= new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-kk-mm"); String strTime = sdf.format(date); str.append(strTime); str.append("</tr><tr>Status:Pass "); str.append(succNum); str.append(" Faild "); str.append(failNum); str.append(" Ratio:"); str.append(((Float.parseFloat(succNum+"")/(succNum+failNum)*100)/100)*100+"%"); str.append("</tr><tr>Detail Views</tr>"); str.append("<tr bgcolor='#CCCCCC'>\n"); str.append("<td>\n"); str.append("TestCase\n"); str.append("</td>\n"); str.append("<td>\n"); str.append("time\n"); str.append("</td>\n"); str.append("<td >\n"); str.append("total\n"); str.append("</td>\n"); str.append("<td >\n"); str.append("passed\n"); str.append("</td>\n"); str.append("<td >\n"); str.append("Faild\n"); str.append("</td>\n"); str.append("</tr>\n"); //第二行 str.append("<tr bgcolor='B0E0E6'>\n"); str.append("<td>\n"); str.append("Summary\n"); str.append("</td>\n"); str.append("<td>\n"); str.append(totalTime+"s"+"\n"); str.append("</td>\n"); str.append("<td >\n"); str.append(reports.size()+"\n"); str.append("</td>\n"); str.append("<td >\n"); str.append(succNum+"\n"); str.append("</td>\n"); str.append("<td >\n"); str.append(failNum+"\n"); str.append("</td>\n"); str.append("</tr>\n"); for (Report b : reports) { str.append("<tr"); // str.append(" bgcolor='#CD5555'"); str.append(">"); str.append("<td>\n"); str.append(b.getCaseName()); str.append("</td>\n"); str.append("<td>\n"); str.append(b.getTime()+"s"); str.append("</td>\n"); str.append("<td colspan='3' align='center'>\n"); if(!"pass".equals(b.getMessage())) { str.append("<font color='#FF0000'>"); str.append(b.getMessage()); str.append("</font>"); } else { str.append("<font color='#218868'>"); str.append(b.getMessage()); str.append("</font>"); } str.append("</td>\n"); str.append("</tr>\n"); } str.append("</table>\n"); str.append("</body>\n"); str.append("</html>\n"); System.out.println(str.toString()); out.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { generateReports(); } }