最近从mstest转到nunit,原因很简单,mstest如果要脱离IDE单独安装很麻烦,PPE环境下只会安装必要的依赖包,不可能把IDE也装上。相比之下,Nuit就清凉很多了,安装后可以直接用nuit-console.exe来运行测试了。
但问题是测试结果是xml形式的,可读性一般,如下:
1 <?xml version="1.0" encoding="utf-8" standalone="no"?> 2 <?xml-stylesheet type="text/xsl" href="nunitresult.xslt"?> 3 4 <!--This file represents the results of running a test suite--> 5 <test-results name="E:\NUnitTest.dll" total="3" errors="1" failures="0" not-run="0" inconclusive="0" ignored="0" skipped="0" invalid="0" date="2012-07-04" time="10:09:16"> 6 <environment nunit-version="2.6.0.12051" clr-version="2.0.50727.5456" os-version="Microsoft Windows NT 6.1.7601 Service Pack 1" platform="Win32NT" cwd="C:\Program Files\NUnit 2.6\bin" machine-name="Test" user="Tester" user-domain="Test" /> 7 <culture-info current-culture="en-US" current-uiculture="en-US" /> 8 <test-suite type="Assembly" name="E:\NUnitTest.dll" executed="True" result="Failure" success="False" time="0.109" asserts="0"> 9 <results> 10 <test-suite type="Namespace" name="NUnitTest" executed="True" result="Failure" success="False" time="0.103" asserts="0"> 11 <results> 12 <test-suite type="TestFixture" name="Class1" executed="True" result="Failure" success="False" time="0.102" asserts="0"> 13 <results> 14 <test-case name="NUnitTest.Class1.SampleTest1" description="Description1" executed="True" result="Success" success="False" time="0.061" asserts="0"> 15 <failure> 16 <message><![CDATA[Error message from assert fail!!]]></message> 17 <stack-trace><![CDATA[at NUnitTest.Class1.SampleTest1() in E:\NUnitTest\Class1.cs:line 16 18 ]]></stack-trace> 19 </failure> 20 </test-case> 21 <test-case name="NUnitTest.Class1.SampleTest2" description="Description2" executed="True" result="Error" success="False" time="0.002" asserts="0"> 22 <failure> 23 <message><![CDATA[System.Exception : Throwing an new exception!!]]></message> 24 <stack-trace><![CDATA[at NUnitTest.Class1.SampleTest2() in E:\NUnitTest\Class1.cs:line 23 25 ]]></stack-trace> 26 </failure> 27 </test-case> 28 <test-case name="NUnitTest.Class1.SampleTest3" description="Description3" executed="True" result="Success" success="True" time="0.000" asserts="0" /> 29 <test-case name="NUnitTest.Class1.SampleTest4" description="Description4" executed="True" result="Success" success="True" time="0.000" asserts="0" /> 30 </results> 31 </test-suite> 32 </results> 33 </test-suite> 34 </results> 35 </test-suite> 36 </test-results>
于是按照解析mstest测试结果的工具trx2html所生成的html报告的样子,自己写了下面的xslt来解析:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 3 <xsl:template match="/"> 4 <html> 5 <head> 6 <title>@@Title@@</title> 7 <style type='text/css'> 8 body, td, th {font:Verdana;vertical-align:top;text-align:left} 9 body {margin:0px 0px 0px 15px} 10 hr {margin:0px 0px 0px -15px;border:solid 1pt #dcdcdc} 11 table {border-collapse:collapse;border:solid 1px #a9a9a9} 12 th {background-color:#dcdcdc;border:solid 1px #a9a9a9;text-indent:2pt;font-weight:bolder} 13 td {border:solid 1px #a9a9a9} 14 15 span.ok{background-color:lime;color:black;font-size:40%;color:lime;display:inline-block;} 16 span.ko{background-color:red;color:white;font-size:40%;color:red;display:inline-block;} 17 span.ignore{background-color:yellow;color:white;font-size:40%;color:yellow;display:inline-block;} 18 19 p.testKo{ 20 cursor:hand; 21 width:40px; 22 height:40px; 23 background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAUCAIAAAAGHlpnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAPBSURBVDhPY/hPMWDANOHXu1fvTx94v3bmy3kdT6bXP51c9XRi5ctpzS8O7vz57jWmehQj/v398+XKqXfLJ79Z0P5pUce3Re2/5jX9nFn9pb/odUv6w/Koh03Zb88dRzMF2Yh/3y4ce7uw89Pizt+r+v8s7fw1t/7ntIqfEwt/duX8akn5Vhf1MM/3WrrPkz2bkE1BGPH1xvk381q/LO36vbLv18LmX9PKf/bl/ehM/9mc+KM+5nt1+LfywM8FXg8SbM9E2rw8ewxuCtSIv5/ev10+6cOC1t/Lu/+c3g2R/jmz9kdVyM9JxVDuxrmfMhzeJ5pfCNI7kRP++/s3iDjUiK+n9r2eUftrcftvoOMn5P97dh8o9/fJne/VYX8f3QKxH978mGr7IcHiTbThoxDt7c5q97au+fv7N8KIN8snf5ha8WtO/Y9JRT9ak35OLYfY8O/NMxD59dOX8uAP8aZvow2eh2o98lfb7yh/tCTpz9fPCCOeTq7+Mrn0x6Tin51pP2ojvxX7/to0F+7b7ws63scav4vUfx2i+cRP5a6n/FF7qQ2hjj9fv0AYca8950d//o/uzB9Nsd/K/b/muX8tCYAb8SHd4W247psQjZf+yo885W65SJ2wEV3kbvTlznWEEbca0r61pX5vjv9WFfo13+NLluPvM/vhRvw8tuNNkPorP6VnXnL3nSWu2oscNheYY6/98co5hBF3GtLfV4Z/B+ov9P2a6fxz7XSI/u+b5kEYXxZ0vvSUfeQscdNO+Jwl/2YDnoVOel/ug0IaGiMP+2seZ7p/LwDa7/S1Kuzfl09AuR8b574N1vi+cwUoRD9/eBlnds9O+JIF/0lTngWanNsyI/58BimDGvH64PYLMTZvUm0/Jln+unISFIsvHr+NM33tr/Q6XPfPs4cgF505cNWC76Qx1y5djn413ht7d/77+xdhxO9PHy5Wpp4PNnoeafg8TPdZkOazANVnPgrPPGSfuog/chS9ayN4xZz7hBHHXj3W2Socy+P8/4ATBcIIIOvlhVOHwm1PeGnc9lW946V420P2tovkTQexG7aCVyx5z5lxHTPk2KPLMl+VdZql2sNLF+CBjZJTb2/fsMXLcIe93Dkn6YsOEudtRM5ZCZwx4z1mxHlQn22bFutMZdYpBtLnt26E60dxBUT0wZH922PcF5rJrDYU3mrIt8eQZ7sO1xoN9nmq7P1KnHOcDZ8f3YesH4sRoGB78+rKqkWbkoNmOehOsFTvtVSfYqm62Nvi9KS2T08foenHbgSmIvwiACPu1otCSuPAAAAAAElFTkSuQmCC); 24 background-repeat:no-repeat 25 } 26 p.testOk{ 27 cursor:hand; 28 width:40px; 29 height:40px; 30 background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAMTSURBVDhPpdTrL5tRGABw/80+LCKzGHHJqEt19KWoy2sW0a5D0a6hVcWoKu26Tlt1p1Uzd6WoqdVtQ0vEZW6xi2UXsw3r0FKq3ZHKeGUfljgfTvKcnF+ec3nOcbBdoTlcwdou40+/PopHH5M74sk98TQNiTbwIFF5l/AspnRE+O33xqVMCDz+YZSiJNS9kejML7XW7o49heyLRPqWx5t9lNabAEl9VXMdF/05nlx/laFOntjVLNp0mpPOpu2qinWBcInDm83h6JlsPYMxmOwvdG+davzrz/DW/k+mmqI3audt471HLfWbUtEKt3g2m62n502ms8aoJCVM6U8gq+K9i1zefV+z+zPct9QlneMt2CbUx62yjVLhIrtAz8h9TWONpmWOpOLlgUINV7XaTu0hRlRj0ptTEZimSho6UA1alYrNspJlDkjIGqMwhlPp2mRcbUC+imk5sZgth6x+WqwiNLgEhcDUgfv9lrbmnRrRKjdjKDFrNI0xlJKhJUfUBWYr0/cP944sR5U6UVwjLlaB8+a7IDBdS+4yNoITki7zRSM8WAFlDqfg5RhmB/Xw+ABMrdZJIhvuwIoQWB7iK3BDYEofESy4eD57Zkt3bDlmd2ehSz0y2ykms8lqtVZPlUUqMEBG1WHxNUE+fFcEJrZHi1YKOdPMp9PcXbPBZDYWdLNMR0YwqUYvDZej4QYoqi4ovCowtDzAi+uMwLm9dLaOXqBjUDUEsY5nXypotfqyMHlAjAKKkmGBDCnzDxb7YAS3EXhwWU3qjM0Ze5g+kJigjJTNVHw1fC7S5obL0HA9FuSMOJV+kAQF7lmsESCwwWSIKscS26IpfYQkZVxcM47YAoOjjpaDTWJwlWhI6hcsQaGfeLrmOa5triIwCNQLKh/erbiGMFIbHP8cD8ux0TIsKAlcBRoq9Q0WowIEns7Z10pe8C+Xpz3WLKqhEn9QwJAUFVaBxlcHgR57mtDLvcDJJfe6RCP898Owj+7sb7dPN5Fk99zyHd3ZTh6FN0DvxblJries/3h/UZ7X9qXR/wyv9JP8AUelhZbR6oNqAAAAAElFTkSuQmCC); 31 background-repeat:no-repeat 32 } 33 p.testIgnore{ 34 cursor:hand; 35 width:40px; 36 height:40px; 37 background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJeSURBVDhPY/hPAWDApfff328EjcWu+de3J49PWD47a3lym/Xlk0txmYJd89s7kz48UvnxLfDKEb4p1ZJ//vzGqh+L5r+/Pzw5ZfLvj+P//57//0tOreY+f2QWsZo/Pel9f8/h3//QRw9k//6TO7aTc26rGlGa//x8+vK83f+/BQsW+SnKa/d1G/z/zzetmvPCifWY+tGd/eH+1E/3ff//r01MtmFg8A3xsv7/X2j/GqbZLToENP/99fHJSZd/v5r+/8/sbjNkYkiY1a3+/z//15fcE8q47t44jqYfxeZPj2e/ueXz/3/v//+uuzbJKfA3Xjyi9P8Py9/v4ptnsM7rcsCp+d/fj8/Oevz6Vvz/f97//2pHDonqyMfdvSL4/wPDrw+ib66z9ZdyPn9yB1k/wubvr5a9ugb0IVCnw/+//FcvcCV46jy/yfb/GcPPR7x/Pois6GFeNTMSi+Z/fz68OOf+/bPX//9u/z9L/H/J+v8z07NznP/fMvy/w/DzCtOv95JPz3NOLOP9/u0DXD/U5q/PV7w6L/fvv+X/TzL/H7D/e8O8eBqLvy/7poXsQJt/nWP4eovn71vRpe2sy2fEomj+8Pb+9e0W3+9I//8s9f8W2/9bzN+fMViZMjIwxBWnJP5/wfDrLMP3c4x/ngg+Pcg0sd4eRfPrp2e3T+d/tIf7xWG2J7uZHu1gen6IcXk3U1WK2/k1Zo/3MN7Zwnh/K+OjXUwv9jGu6xdH0fz719cbh9Jn1LBPLmMDoklgcloVELFOqWCdVAZEIBEgmlrJuqBDE93PBLMuUWmbJFMAIcChwBwUNxQAAAAASUVORK5CYII=); 38 background-repeat:no-repeat 39 } 40 div.barContainer{width:100%;border:solid 1px black} 41 div.trace{font:100% Courier} 42 div.border{border:dotted 1px #dcdcdc;padding:2px 2px 2px 2px} 43 div.contents{border:dotted 1px #dcdcdc;padding:2px 2px 2px 2px;background-color:#efefef} 44 </style> 45 </head> 46 <body> 47 <a name='__top' /> 48 <h3>@@Title@@</h3> 49 <div class='contents'> 50 Summary 51 </div> 52 <br /> 53 <a name='totals' /> 54 <table id='tMainSummary' border='0' width='900px'> 55 <tr> 56 <th>Percent</th> 57 <th>Status</th> 58 <th>TotalTests</th> 59 <th>Errors</th> 60 <th>Failures</th> 61 <th>NotRun</th> 62 <th>Inconclusive</th> 63 <th>Ignored</th> 64 <th>Skipped</th> 65 <th>Invalid</th> 66 <th>TimeTaken</th> 67 </tr> 68 <tr> 69 <xsl:apply-templates /> 70 </tr> 71 </table> 72 <br /> 73 <br /> 74 <div class='contents'> 75 Detail 76 </div> 77 <br /> 78 <table id="tSlowerMethods" border='0' width='900px'> 79 <tr> 80 <th>TestMethod</th> 81 <th colspan='2'>Status</th> 82 <th>Duration</th> 83 </tr> 84 <xsl:for-each select="//test-case"> 85 <tr> 86 <td><xsl:value-of select="@name"/></td> 87 <td> 88 <xsl:choose> 89 <xsl:when test="@result = 'Success'"> 90 <p class='testOk'></p> 91 </xsl:when> 92 <xsl:otherwise> 93 <p class='testKo'></p> 94 </xsl:otherwise> 95 </xsl:choose> 96 </td> 97 <td width='100%'> 98 <xsl:value-of select="@description"/><br /> 99 <xsl:value-of select="failure/message"/><br /> 100 <xsl:value-of select="failure/stack-trace"/> 101 </td> 102 <td><xsl:value-of select="@time"/></td> 103 </tr> 104 </xsl:for-each> 105 </table> 106 </body> 107 </html> 108 </xsl:template> 109 110 <xsl:template match="test-results"> 111 <td> 112 <xsl:value-of 113 select="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>% 114 </td> 115 <td width='350px' style='vertical-align:middle;font-size:200%'> 116 <div class="barContainer"> 117 <span class="ok" title="Passed!"> 118 <xsl:attribute name="style"> 119 width:<xsl:value-of select="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>% 120 </xsl:attribute>p</span> 121 <span class="ko" title="Failed"> 122 <xsl:attribute name="style"> 123 width:<xsl:value-of select="100-round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>% 124 </xsl:attribute> 125 f</span> 126 </div> 127 </td> 128 <td><xsl:value-of select="@total"/></td> 129 <td><xsl:value-of select="@errors"/></td> 130 <td><xsl:value-of select="@failures"/></td> 131 <td><xsl:value-of select="@not-run"/></td> 132 <td><xsl:value-of select="@inconclusive"/></td> 133 <td><xsl:value-of select="@ignored"/></td> 134 <td><xsl:value-of select="@skipped"/></td> 135 <td><xsl:value-of select="@invalid"/></td> 136 <td><xsl:value-of select="@date"/> <xsl:value-of select="@time"/></td> 137 </xsl:template> 138 </xsl:stylesheet>
其中css样式是抄trx2html报告的,并做了一些改动。
这是解析后的样子:
加了个@@Title@@可以在解析代码中替换为想要的标题。
好了,之后就写个工具解析和生成html report文件吧:
using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
namespace NUnitHtmlTestResultParser
{
class Program
{
static int Main(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine(HelpInfo());
return 1;
}
if (!File.Exists(args[0]))
{
Console.WriteLine("Can not find result file " + args[0]);
Console.WriteLine(HelpInfo());
return 2;
}
try
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(args[0]);
string returnhtml = ConvertXML(xDoc, @"nunitresult.xslt", new XsltArgumentList()).Replace("@@Title@@", args[2]);
using (TextWriter tw = new StreamWriter(args[1]))
{
tw.Write(returnhtml);
}
Console.WriteLine("Done!!");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(HelpInfo());
return 1;
}
return 0;
}
private static string HelpInfo()
{
return "Usage: NUnitHtmlTestResultParser.exe SOURCE DEST TITLE" + System.Environment.NewLine +
"SOURCE is nunit test result file" + System.Environment.NewLine +
"DEST is parsed html test result file" + System.Environment.NewLine +
"TITLE is test report title" + System.Environment.NewLine;
}
private static string ConvertXML(XmlDocument InputXMLDocument, string XSLTFilePath
, XsltArgumentList XSLTArgs)
{
using (StringWriter sw = new StringWriter())
{
XslCompiledTransform xslTrans = new XslCompiledTransform();
xslTrans.Load(XSLTFilePath);
xslTrans.Transform(InputXMLDocument.CreateNavigator(), XSLTArgs, sw);
return sw.ToString();
}
}
}
}
好了,试试这个工具:
$ NUnitHtmlTestResultParser.exe result.xml result.html “Test result for abc”
$ Done!!
打开result.html看看:
由于我的测试结果是要通过邮件发出的,并且都是通过outlook收发邮件的,如果以上面这种html直接发到邮箱里面的话,展现的结果是这个鬼样子:
好吧,继续修改之前的xslt,使其能在outlook中显示正常:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head> <title>@@Title@@</title> <style type='text/css'> body, td, th {font:Verdana;vertical-align:top;text-align:left} body {margin:0px 0px 0px 15px} hr {margin:0px 0px 0px -15px;border:solid 1pt #dcdcdc} table {border-collapse:collapse;border:solid 1px #a9a9a9} th {background-color:#dcdcdc;border:solid 1px #a9a9a9;text-indent:2pt;font-weight:bolder} td {border:solid 1px #a9a9a9} span.ok{background-color:lime;color:black;font-size:40%;color:lime;display:inline-block;} span.ko{background-color:red;color:white;font-size:40%;color:red;display:inline-block;} span.ignore{background-color:yellow;color:white;font-size:40%;color:yellow;display:inline-block;} p.testKo{ cursor:hand; width:40px; height:40px; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAUCAIAAAAGHlpnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAPBSURBVDhPY/hPMWDANOHXu1fvTx94v3bmy3kdT6bXP51c9XRi5ctpzS8O7vz57jWmehQj/v398+XKqXfLJ79Z0P5pUce3Re2/5jX9nFn9pb/odUv6w/Koh03Zb88dRzMF2Yh/3y4ce7uw89Pizt+r+v8s7fw1t/7ntIqfEwt/duX8akn5Vhf1MM/3WrrPkz2bkE1BGPH1xvk381q/LO36vbLv18LmX9PKf/bl/ehM/9mc+KM+5nt1+LfywM8FXg8SbM9E2rw8ewxuCtSIv5/ev10+6cOC1t/Lu/+c3g2R/jmz9kdVyM9JxVDuxrmfMhzeJ5pfCNI7kRP++/s3iDjUiK+n9r2eUftrcftvoOMn5P97dh8o9/fJne/VYX8f3QKxH978mGr7IcHiTbThoxDt7c5q97au+fv7N8KIN8snf5ha8WtO/Y9JRT9ak35OLYfY8O/NMxD59dOX8uAP8aZvow2eh2o98lfb7yh/tCTpz9fPCCOeTq7+Mrn0x6Tin51pP2ojvxX7/to0F+7b7ws63scav4vUfx2i+cRP5a6n/FF7qQ2hjj9fv0AYca8950d//o/uzB9Nsd/K/b/muX8tCYAb8SHd4W247psQjZf+yo885W65SJ2wEV3kbvTlznWEEbca0r61pX5vjv9WFfo13+NLluPvM/vhRvw8tuNNkPorP6VnXnL3nSWu2oscNheYY6/98co5hBF3GtLfV4Z/B+ov9P2a6fxz7XSI/u+b5kEYXxZ0vvSUfeQscdNO+Jwl/2YDnoVOel/ug0IaGiMP+2seZ7p/LwDa7/S1Kuzfl09AuR8b574N1vi+cwUoRD9/eBlnds9O+JIF/0lTngWanNsyI/58BimDGvH64PYLMTZvUm0/Jln+unISFIsvHr+NM33tr/Q6XPfPs4cgF505cNWC76Qx1y5djn413ht7d/77+xdhxO9PHy5Wpp4PNnoeafg8TPdZkOazANVnPgrPPGSfuog/chS9ayN4xZz7hBHHXj3W2Socy+P8/4ATBcIIIOvlhVOHwm1PeGnc9lW946V420P2tovkTQexG7aCVyx5z5lxHTPk2KPLMl+VdZql2sNLF+CBjZJTb2/fsMXLcIe93Dkn6YsOEudtRM5ZCZwx4z1mxHlQn22bFutMZdYpBtLnt26E60dxBUT0wZH922PcF5rJrDYU3mrIt8eQZ7sO1xoN9nmq7P1KnHOcDZ8f3YesH4sRoGB78+rKqkWbkoNmOehOsFTvtVSfYqm62Nvi9KS2T08foenHbgSmIvwiACPu1otCSuPAAAAAAElFTkSuQmCC); background-repeat:no-repeat } p.testOk{ cursor:hand; width:40px; height:40px; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAMTSURBVDhPpdTrL5tRGABw/80+LCKzGHHJqEt19KWoy2sW0a5D0a6hVcWoKu26Tlt1p1Uzd6WoqdVtQ0vEZW6xi2UXsw3r0FKq3ZHKeGUfljgfTvKcnF+ec3nOcbBdoTlcwdou40+/PopHH5M74sk98TQNiTbwIFF5l/AspnRE+O33xqVMCDz+YZSiJNS9kejML7XW7o49heyLRPqWx5t9lNabAEl9VXMdF/05nlx/laFOntjVLNp0mpPOpu2qinWBcInDm83h6JlsPYMxmOwvdG+davzrz/DW/k+mmqI3audt471HLfWbUtEKt3g2m62n502ms8aoJCVM6U8gq+K9i1zefV+z+zPct9QlneMt2CbUx62yjVLhIrtAz8h9TWONpmWOpOLlgUINV7XaTu0hRlRj0ptTEZimSho6UA1alYrNspJlDkjIGqMwhlPp2mRcbUC+imk5sZgth6x+WqwiNLgEhcDUgfv9lrbmnRrRKjdjKDFrNI0xlJKhJUfUBWYr0/cP944sR5U6UVwjLlaB8+a7IDBdS+4yNoITki7zRSM8WAFlDqfg5RhmB/Xw+ABMrdZJIhvuwIoQWB7iK3BDYEofESy4eD57Zkt3bDlmd2ehSz0y2ykms8lqtVZPlUUqMEBG1WHxNUE+fFcEJrZHi1YKOdPMp9PcXbPBZDYWdLNMR0YwqUYvDZej4QYoqi4ovCowtDzAi+uMwLm9dLaOXqBjUDUEsY5nXypotfqyMHlAjAKKkmGBDCnzDxb7YAS3EXhwWU3qjM0Ze5g+kJigjJTNVHw1fC7S5obL0HA9FuSMOJV+kAQF7lmsESCwwWSIKscS26IpfYQkZVxcM47YAoOjjpaDTWJwlWhI6hcsQaGfeLrmOa5triIwCNQLKh/erbiGMFIbHP8cD8ux0TIsKAlcBRoq9Q0WowIEns7Z10pe8C+Xpz3WLKqhEn9QwJAUFVaBxlcHgR57mtDLvcDJJfe6RCP898Owj+7sb7dPN5Fk99zyHd3ZTh6FN0DvxblJries/3h/UZ7X9qXR/wyv9JP8AUelhZbR6oNqAAAAAElFTkSuQmCC); background-repeat:no-repeat } p.testIgnore{ cursor:hand; width:40px; height:40px; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJeSURBVDhPY/hPAWDApfff328EjcWu+de3J49PWD47a3lym/Xlk0txmYJd89s7kz48UvnxLfDKEb4p1ZJ//vzGqh+L5r+/Pzw5ZfLvj+P//57//0tOreY+f2QWsZo/Pel9f8/h3//QRw9k//6TO7aTc26rGlGa//x8+vK83f+/BQsW+SnKa/d1G/z/zzetmvPCifWY+tGd/eH+1E/3ff//r01MtmFg8A3xsv7/X2j/GqbZLToENP/99fHJSZd/v5r+/8/sbjNkYkiY1a3+/z//15fcE8q47t44jqYfxeZPj2e/ueXz/3/v//+uuzbJKfA3Xjyi9P8Py9/v4ptnsM7rcsCp+d/fj8/Oevz6Vvz/f97//2pHDonqyMfdvSL4/wPDrw+ib66z9ZdyPn9yB1k/wubvr5a9ugb0IVCnw/+//FcvcCV46jy/yfb/GcPPR7x/Pois6GFeNTMSi+Z/fz68OOf+/bPX//9u/z9L/H/J+v8z07NznP/fMvy/w/DzCtOv95JPz3NOLOP9/u0DXD/U5q/PV7w6L/fvv+X/TzL/H7D/e8O8eBqLvy/7poXsQJt/nWP4eovn71vRpe2sy2fEomj+8Pb+9e0W3+9I//8s9f8W2/9bzN+fMViZMjIwxBWnJP5/wfDrLMP3c4x/ngg+Pcg0sd4eRfPrp2e3T+d/tIf7xWG2J7uZHu1gen6IcXk3U1WK2/k1Zo/3MN7Zwnh/K+OjXUwv9jGu6xdH0fz719cbh9Jn1LBPLmMDoklgcloVELFOqWCdVAZEIBEgmlrJuqBDE93PBLMuUWmbJFMAIcChwBwUNxQAAAAASUVORK5CYII=); background-repeat:no-repeat } div.barContainer{width:100%;border:solid 1px black} div.trace{font:100% Courier} div.border{border:dotted 1px #dcdcdc;padding:2px 2px 2px 2px} div.contents{border:dotted 1px #dcdcdc;padding:2px 2px 2px 2px;background-color:#efefef} </style> </head> <body> <a name='__top' /> <h3>@@Title@@</h3> <div class='contents'> Summary </div> <br /> <a name='totals' /> <table id='tMainSummary' border='0' width="1000"> <tr> <th width="40">Percent</th> <th width="150">Status</th> <th width="40">TotalTests</th> <th width="40">Errors</th> <th width="40">Failures</th> <th width="40">NotRun</th> <th width="40">Inconclusive</th> <th width="40">Ignored</th> <th width="40">Skipped</th> <th width="40">Invalid</th> <th width="40">TimeTaken</th> </tr> <tr> <xsl:apply-templates /> </tr> </table> <br /> <br /> <div class='contents'> Detail </div> <br /> <table id="tSlowerMethods" border='0' width="1000"> <tr> <th width="202">TestMethod</th> <th width="58">Status</th> <th width="661">Message</th> <th width="79">Duration</th> </tr> <xsl:for-each select="//test-case"> <tr> <td><xsl:value-of select="@name"/></td> <td> <xsl:choose> <xsl:when test="@result = 'Success'"> <div style="color: #008000; font-weight: bolder">PASS</div> </xsl:when> <xsl:otherwise> <div style="color: #FF0000; font-weight: bolder">FAIL</div> </xsl:otherwise> </xsl:choose> </td> <td> <xsl:value-of select="@description"/><br /> <xsl:value-of select="failure/message"/><br /> <xsl:value-of select="failure/stack-trace"/> </td> <td><xsl:value-of select="@time"/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> <xsl:template match="test-results"> <td> <xsl:value-of select="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>% </td> <td width='350px' style='vertical-align:middle;font-size:200%'> <table border="0" width="100%"> <tr> <xsl:choose> <xsl:when test="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100) = 100"> <td bgcolor="Green" style="color: #008000" width="100%">P</td> </xsl:when> <xsl:when test="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100) = 0"> <td bgcolor="Red" style="color: #FF0000" width="100%">F</td> </xsl:when> <xsl:otherwise> <td bgcolor="Green" style="color: #008000"><xsl:attribute name="width"><xsl:value-of select="round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>%</xsl:attribute>P</td> <td bgcolor="Red" style="color: #FF0000"><xsl:attribute name="width"> <xsl:value-of select="100-round(((number(@total)-number(@errors)-number(@failures)-number(@not-run)-number(@inconclusive)-number(@ignored)-number(@skipped)-number(@invalid)) div @total) * 100)"/>%</xsl:attribute>F</td> </xsl:otherwise> </xsl:choose> </tr> </table> </td> <td><xsl:value-of select="@total"/></td> <td><xsl:value-of select="@errors"/></td> <td><xsl:value-of select="@failures"/></td> <td><xsl:value-of select="@not-run"/></td> <td><xsl:value-of select="@inconclusive"/></td> <td><xsl:value-of select="@ignored"/></td> <td><xsl:value-of select="@skipped"/></td> <td><xsl:value-of select="@invalid"/></td> <td><xsl:value-of select="@date"/> <xsl:value-of select="@time"/></td> </xsl:template> </xsl:stylesheet>