用DCG做单元测试报表
最近因为工作需要写了个将NUnit的XML结果输出转成报表的动态模板,我制作的样式虽然不太好看不过倒瞒实用的,有兴趣的朋友也可以去下载DCG来生成自己的报表哦!
下面是报表的示例。
D:\Visual Studio Projects\PWF-Framework\Framework\bin\Debug-UnitTests\PWF.Framework.exe | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
用例数量 | 27 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
失败个数 | 0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
没运行个数 | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
日期 | 2005-4-15 9:38 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
准备人 | Seth Yuan | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
下面是相关的两个模板文件的内容:
UnitTestReport.dt
<%@ Template Name="" Language="C#" %>
<%@ Assembly Location="system.xml.dll" %>
<%@ Import Namespace="System.Xml" %>
<%@ Parameter Name="title" DataType="String" %>
<%@ Parameter Name="preparedBy" DataType="String" %>
<%@ Parameter Name="reportFileName" DataType="String" %>
<%
if (reportFileName == null || reportFileName.Length == 0) {
throw new ArgumentNullException("reportFileName");
}
XmlDocument doc = new XmlDocument();
doc.Load(reportFileName);
%>
<html>
<head>
<title><%=title%></title>
</head>
<body>
<TABLE cellSpacing="0" cellPadding="1" width="90%" align="center" border="0">
<!--DWLayoutTable-->
<TR>
<TD height="50" colspan="2" valign="top">
<P align="center"><FONT color="navy" size="5" face="黑体"><STRONG><%=doc.DocumentElement.Attributes["name"].Value%></STRONG></FONT></P></TD>
</TR>
<TR bgcolor="#FFFF99">
<TD width="97"><font size="2"><strong>用例数量</strong></font></TD>
<TD width="538" bgcolor="#FFFFCC"><font size="2"><%=doc.DocumentElement.Attributes["total"].Value%></font></TD>
</TR>
<TR bgcolor="#FFFF99">
<TD><font size="2"><strong>失败个数</strong></font></TD>
<TD bgcolor="#FFFFCC"><font color="#FF0000" size="2"><%=doc.DocumentElement.Attributes["failures"].Value%></font></TD>
</TR>
<TR bgcolor="#FFFF99">
<TD><font size="2"><strong>没运行个数</strong></font></TD>
<TD bgcolor="#FFFFCC"><font color="#FF9900" size="2"><%=doc.DocumentElement.Attributes["not-run"].Value%></font></TD>
</TR>
<TR bgcolor="#FFFF99">
<TD><font size="2"><strong>日期</strong></font></TD>
<TD bgcolor="#FFFFCC"><font size="2"><%=doc.DocumentElement.Attributes["date"].Value + " " + doc.DocumentElement.Attributes["time"].Value%></font></TD>
</TR>
<TR bgcolor="#FFFF99">
<TD><font size="2"><strong>准备人</strong></font></TD>
<TD bgcolor="#FFFFCC"><font size="2"><%=preparedBy%></font></TD>
</TR>
<TR>
<TD height="144" colspan="2" valign="top">
<% XmlNodeList testSuites = doc.DocumentElement.SelectNodes("/descendant::test-suite[./results/test-case]"); %>
<% foreach (XmlNode testSuiteNode in testSuites) { %>
<%= DCG.CallTemplate(DCG.FileInfo.Directory + "\\UnitTestReport-TestSuite.dt", new object[] {testSuiteNode}) %>
<% } %>
</TD>
</TR>
</TABLE>
</body>
</html>
<%@ Template Name="" Language="C#" %>UnitTestReport-TestSuite.dt
<%@ Template Name="" Language="C#" %><%@ Template Name="" Language="C#" %>
<%@ Assembly Location="system.xml.dll" %>
<%@ Import Namespace="System.Xml" %>
<%@ Parameter Name="testSuiteNode" DataType="XmlNode" %>
<TABLE cellSpacing="0" cellPadding="1" width="100%" border="0">
<TR>
<TD colSpan="5" height="40">
<P align="center"><STRONG><FONT color="navy" size="4" face="黑体"><%=testSuiteNode.Attributes["name"].Value%></FONT></STRONG></P>
</TD>
</TR>
<TR>
<TD valign="top">
<P align="left"><FONT size="2"><STRONG>描述</STRONG></FONT></P>
</TD>
<TD colspan="4" valign="top">
<% if (testSuiteNode.Attributes["description"] != null) { %>
<P align="left"><font size="2"><%=testSuiteNode.Attributes["description"].Value%></font></P>
<% } %>
</TD>
</TR>
<TR>
<TD width="15%" valign="top">
<P align="left"><FONT size="2"><STRONG>结果</STRONG></FONT></P>
</TD>
<TD colspan="4" valign="top" width=".">
<% if (testSuiteNode.Attributes["success"] != null) { %>
<%-- 如果成功就用绿色,如果失败就用红色 --%>
<% bool success = bool.Parse(testSuiteNode.Attributes["success"].Value); %>
<% if (success) { %>
<P align="left"><FONT color="#009900" size="2">成功</FONT></P>
<% } else { %>
<P align="left"><FONT color="#FF0000" size="2">失败</FONT></P>
<% } %>
<% } %>
</TD>
</TR>
<TR>
<TD valign="top">
<P align="left"><FONT size="2"><STRONG>所用时间</STRONG></FONT></P>
</TD>
<TD colspan="4" valign="top">
<% if (testSuiteNode.Attributes["time"] != null) { %>
<P align="left"><FONT size="2"><%=testSuiteNode.Attributes["time"].Value%></FONT></P>
<% } %>
</TD>
</TR>
<TR>
<TD height="30" colspan="2">
<P align="center"><font size="2"><strong>描述</strong></font></P>
</TD>
<TD width="61">
<P align="center"><font size="2"><strong>已运行</strong></font></P>
</TD>
<TD width="55">
<P align="center"><font size="2"><strong>结果</strong></font></P>
</TD>
<TD width="78">
<P align="center"><font size="2"><strong>所用时间</strong></font></P>
</TD>
</TR>
<% bool firstLine = true; %>
<% XmlNodeList testCases = testSuiteNode.SelectNodes("results/test-case"); %>
<% foreach (XmlNode testCaseNode in testCases) { %>
<% if (firstLine) { %>
<TR bgcolor="gainsboro">
<TD colspan="2">
<% if (testCaseNode.Attributes["description"] != null) { %>
<P align="left"><FONT size="2"><%=testCaseNode.Attributes["description"].Value%></FONT></P>
<% } %>
</TD>
<TD>
<P align="center"><FONT size="2"><%=(bool.Parse(testCaseNode.Attributes["executed"].Value) ? "是" : "否")%></FONT></P>
</TD>
<TD>
<% if (testCaseNode.Attributes["success"] != null) { %>
<%-- 如果成功就用绿色,如果失败就用红色 --%>
<% bool success2 = bool.Parse(testCaseNode.Attributes["success"].Value); %>
<% if (success2) { %>
<P align="left"><FONT color="#009900" size="2">成功</FONT></P>
<% } else { %>
<P align="left"><FONT color="#FF0000" size="2">失败</FONT></P>
<% } %>
<% } %>
</TD>
<TD>
<% if (testCaseNode.Attributes["time"] != null) { %>
<P align="center"><FONT size="2"><%=testCaseNode.Attributes["time"].Value%></FONT></P>
<% } %>
</TD>
</TR>
<% } else { %>
<TR bgcolor="beige">
<TD colspan="2">
<% if (testCaseNode.Attributes["description"] != null) { %>
<P align="left"><FONT size="2"><%=testCaseNode.Attributes["description"].Value%></FONT></P>
<% } %>
</TD>
<TD>
<P align="center"><FONT size="2"><%=(bool.Parse(testCaseNode.Attributes["executed"].Value) ? "是" : "否")%></FONT></P>
</TD>
<TD>
<% if (testCaseNode.Attributes["success"] != null) { %>
<%-- 如果成功就用绿色,如果失败就用红色 --%>
<% bool success3 = bool.Parse(testCaseNode.Attributes["success"].Value); %>
<% if (success3) { %>
<P align="left"><FONT color="#009900" size="2">成功</FONT></P>
<% } else { %>
<P align="left"><FONT color="#FF0000" size="2">失败</FONT></P>
<% } %>
<% } %>
</TD>
<TD>
<% if (testCaseNode.Attributes["time"] != null) { %>
<P align="center"><FONT size="2"><%=testCaseNode.Attributes["time"].Value%></FONT></P>
<% } %>
</TD>
</TR>
<% } %>
<% firstLine = ! firstLine; %>
<% } %>
</TABLE>
还不知道的DCG的朋友,它是我做的一个动态代码生成器,其目的与CodeSmith一样,就是一个动态模板,更多关于DCG请看我Blog中的文章部分。
其实我也完全可以用XSLT来做这个转换,可是我很清楚XSLT的限制,而且它的语法布局不是特别的清晰,而且函数有限,总之做起来不直观,很慢。我更喜欢ASP的语法,这也是为什么我选择并制作了DCG。你问我为什么不用CodeSmith?因为我不太喜欢它的扩展方法,因为它不够开放,因为它的功能不够达到我的目的,很多的原因使我选择了自己制作。