zoukankan      html  css  js  c++  java
  • 使用XSLT生成Nunit测试报告

    最近从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                 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                 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                 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{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                         <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                         <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"/>&#160;<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;
                    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;
                    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;
                    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{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>

    好了,再通过outlook看看:

    搞定。

     

  • 相关阅读:
    C++ 设计模式 —— 訪问者(Visitor)
    图解IIS配置过程
    JSBridge
    10大H5前端框架,让你开发不愁
    具体解释java中的volatilekeyword
    网速变慢解决方法.Tracert与PathPing(转)
    最快下载速度100Mbps!4G LTE技术全解析
    Windows客户端的JProfiler远程监控Linux上的Tomcat
    Java内存泄露原因详解
    JProfiler 解决 Java 服务器的性能跟踪
  • 原文地址:https://www.cnblogs.com/liupengblog/p/2678477.html
Copyright © 2011-2022 走看看