用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

ConditionSyntaxTest

描述

测试条件表达式的语法

结果

成功

所用时间

0.15625

描述

已运行

结果

所用时间

一个有变量的表达式
$fe > 3 and faLse <> true

成功

0.063

一个Not变量表达式
not $_fe

成功

0.000

有括号的复杂一点的表达式
((true and false = false or false = not true)>= false) < true

成功

0.016

更为复杂的表达式
(("a"<>"A")>=("123"<"456") or (123>345)) and (($_v=true) or (1<=2)) and not (false)

成功

0.000

多重括号表达式
not (true and (false or (true and (false or (true and (false or not ($_v<>true)))))))

成功

0.016

FlowCompilerTest

描述

测试流程编译器的正确性。

结果

成功

所用时间

1.65625

描述

已运行

结果

所用时间

测试对流程定义对象的代码生成,生成期间无异常便通过。

成功

0.906

模拟一个请假流程的定义,然后试图编译,看是否编译出错,不出错既是通过。

成功

0.719

FlowDefinitionTest

描述

测试流程定义对象的准确性

结果

成功

所用时间

1.375

描述

已运行

结果

所用时间

测试签核节点的At属性为空时的处理,应抛出异常。

成功

0.000

测试条件逻辑块对象的ConditionExpression属性为空时的处理,应抛出异常。

成功

0.000

测试签核条件对象的ConditionExpression属性为空时的处理,应抛出异常。

成功

0.000

测试ExternalProgramCallLB对象的ExePath属性为空时的处理,应抛出异常。

成功

0.016

测试流程定义对象的序列化

成功

1.063

又一个更复杂的序列化测试

成功

0.016

测试流程定义对象名字有非法字符串时的处理(空格),应抛出异常。

成功

0.000

测试流程定义对象名字有非法字符串时的处理(特殊字符),应抛出异常。

成功

0.016

测试流程定义对象为空时的处理,应抛出异常。

成功

0.000

测试流程节点对象的条件属性为空时的处理,应抛出异常。

成功

0.000

测试流程节点对象的唯一名字为空时的处理,应抛出异常。

成功

0.000

测试FlowPropertyChangeLB对象的PropName属性为空时的处理,应抛出异常。

成功

0.016

测试FlowPropertyChangeLB对象的PropValue属性为空时的处理,应抛出异常。

成功

0.000

测试FlowStateChangeLB对象的Description属性为空时的处理,应抛出异常。

成功

0.016

测试流程定义对象的唯一名字为空时的处理,应抛出异常。

成功

0.016

测试JumpToNodeLB对象的Node属性为空时的处理,应抛出异常。

成功

0.000

测试JumpToNodeLB对象的PrevNode属性为空时的处理,应抛出异常。

成功

0.000

测试Param对象的Value属性为空时的处理,应抛出异常。

成功

0.000

测试流程属性对象的初始值为空时的处理,应抛出异常。

成功

0.000

测试流程属性对象的名字为空时的处理,应抛出异常。

成功

0.000

测试流程属性对象的类型为空时的处理,应抛出异常。

下面是相关的两个模板文件的内容:

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?因为我不太喜欢它的扩展方法,因为它不够开放,因为它的功能不够达到我的目的,很多的原因使我选择了自己制作。

posted @ 2005-04-15 21:54  Cavingdeep  阅读(785)  评论(1编辑  收藏  举报