第一次写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, "time", String.format("%.3f", new Object[] {Float.valueOf(time)}));
this.mTestSuiteSerializer.startTag(null, "result");
this.mTestSuiteSerializer.attribute(null, "message", "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, Helvetica, 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();
}
}