Gavin Stevens's Blog

the ramblings of another developer....

  Home  |   Contact  |   Syndication    |   Login
  32 Posts | 0 Stories | 43 Comments | 215 Trackbacks

News

Archives

Tuesday, August 25, 2009 #

VS 2008 requires you have VS 2008 Test Edition to see the results of a Generic Test, this wasn't sufficient with out current project as a lot of developers don't use test edition.  I put together this custom xslt transform to convert the .trx test result file to an html report anyone can view, complete with collapsable sections...

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:vs="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
  <xsl:template match="/">
    <html>
      <head>
        <style type="text/css">
          input.button {
          color: #fff; background: #0034D0;
          font-size: .8em;
          font-weight:bold;
          font-family: Verdana, Arial, Helvetica, sans-serif;
          border: solid 1px #ffcf31;
          }
        </style>
        <script language="JavaScript">
          function toggleMe(a)
          {
          var e=document.getElementById(a);
          if(!e)return true;
          if(e.style.display=="none"){
          e.style.display="block"
          } else {
          e.style.display="none"
          }
          return true;
          }
        </script>
      </head>
      <body style="font-family:Verdana; font-size:10pt">
        <h1>Test Results Summary</h1>
        <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt;">
          <tr>
            <td width="150">
              <b>Start Date/Time</b>
            </td>
            <td width="550">
              <xsl:value-of select="//vs:Times/@start"/>
            </td>
          </tr>
          <tr>
            <td width="150">
              <b>End Date/Time</b>
            </td>
            <td width="550">
              <xsl:value-of select="//vs:Times/@finish"/>
            </td>
          </tr>
          <tr>
            <td width="150">
              <b>Total Time</b>
            </td>
            <td width="550">
              <xsl:value-of select="//vs:Results/vs:TestResultAggregation/@duration"/>
            </td>
          </tr>
          <tr>
            <td width="150">
              <b>Results</b>
            </td>
            <td width="550">
              <xsl:value-of select="//vs:TestRun/@name"/>
            </td>
          </tr>
        </table>
        <xsl:call-template name="summary" />
        <xsl:call-template name="details" />
      </body>
    </html>
  </xsl:template>
  <xsl:template name="summary">
    <h3>Test Summary</h3>
    <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt">
      <tr>
        <td style="font-weight:bold">Total</td>
        <td style="font-weight:bold">Failed</td>
        <td style="font-weight:bold">Passed</td>
      </tr>
      <tr>
        <td >
          <xsl:value-of select="//vs:ResultSummary/vs:Counters/@total"/>
        </td>
        <td style="background-color:pink;">
          <xsl:value-of select="//vs:ResultSummary/vs:Counters/@failed"/>
        </td>
        <td style="background-color:lightgreen;">
          <xsl:value-of select="//vs:ResultSummary/vs:Counters/@passed"/>
        </td>
      </tr>
    </table>
  </xsl:template>
  <xsl:template name="details">
    <h3>Test Details</h3>
    <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt;">
      <tr>
        <td style="font-weight:bold">Test Name</td>
        <td style="font-weight:bold">Result</td>
        <td style="font-weight:bold">Duration</td>
      </tr>
      <xsl:for-each select="//vs:Results/vs:TestResultAggregation/vs:InnerResults/vs:TestResultAggregation">
        <xsl:variable name="executionId">
          <xsl:value-of select="@executionId"/>
        </xsl:variable>
        <tr>
          <xsl:attribute name="style">
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">background-color:pink;</xsl:when>
              <xsl:when test="@outcome = 'Passed'">background-color:lightgreen;</xsl:when>
              <xsl:otherwise>background-color:yellow;</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
          <td>
            <xsl:value-of select="@testName"/>
          </td>
          <td>
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">FAILED</xsl:when>
              <xsl:when test="@outcome = 'Passed'">Passed</xsl:when>
              <xsl:otherwise>Inconclusive</xsl:otherwise>
            </xsl:choose>
          </td>
          <td>
            <xsl:value-of select="@duration"/>
          </td>
        </tr>
        <tr>
          <td colspan="3">
            <input type="button" class="button" onclick="return toggleMe('{$executionId}')" value="Show Details" />
            <div style="display:none" id="{$executionId}">
              <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt;">
                <tr>
                  <td colspan="3">
                    <xsl:for-each select="vs:InnerResults/vs:GenericTestResult">
                      <table style="width:700;border:1px solid black;font-family:Verdana;font-size:8pt;table-layout:fixed;">
                        <tr>
                          <td width="10"></td>
                          <td>
                            <b>
                              <xsl:value-of select="@testName"/>
                            </b>
                          </td>
                        </tr>
                        <tr>
                          <td width="10"></td>
                          <td>
                            <pre style="word-wrap: break-word">
                              <xsl:value-of select="vs:Output/vs:StdOut"/>
                            </pre>
                          </td>
                        </tr>
                      </table>
                    </xsl:for-each>
                  </td>
                </tr>
              </table>
            </div>
          </td>
        </tr>
      </xsl:for-each>
      <xsl:for-each select="//vs:Results/vs:TestResultAggregation/vs:InnerResults/vs:GenericTestResult">
        <xsl:variable name="executionId">
          <xsl:value-of select="@executionId"/>
        </xsl:variable>
        <tr>
          <xsl:attribute name="style">
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">background-color:pink;</xsl:when>
              <xsl:when test="@outcome = 'Passed'">background-color:lightgreen;</xsl:when>
              <xsl:otherwise>background-color:yellow;</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
          <td>
            <xsl:value-of select="@testName"/>
          </td>
          <td>
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">FAILED</xsl:when>
              <xsl:when test="@outcome = 'Passed'">Passed</xsl:when>
              <xsl:otherwise>Inconclusive</xsl:otherwise>
            </xsl:choose>
          </td>
          <td>
            <xsl:value-of select="@duration"/>
          </td>
        </tr>
        <tr>
          <td colspan="3">
            <input type="button" class="button" onclick="return toggleMe('{$executionId}')" value="Show Details" />
            <div style="display:none" id="{$executionId}">
              <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt;">
                <tr>
                  <td colspan="3">
                    <table style="width:700;border:1px solid black;font-family:Verdana; font-size:8pt;table-layout:fixed;">
                      <tr>
                        <td width="10"></td>
                      </tr>
                      <tr>
                        <td width="10"></td>
                        <td>
                          <pre style="word-wrap: break-word">
                            <xsl:value-of select="vs:Output/vs:StdOut"/>
                          </pre>
                        </td>
                      </tr>
                    </table>
                  </td>
                </tr>
              </table>
            </div>
          </td>
        </tr>
      </xsl:for-each>
      <xsl:for-each select="//vs:Results/vs:TestResultAggregation/vs:InnerResults/vs:UnitTestResult">
        <xsl:variable name="executionId">
          <xsl:value-of select="@executionId"/>
        </xsl:variable>
        <tr>
          <xsl:attribute name="style">
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">background-color:pink;</xsl:when>
              <xsl:when test="@outcome = 'Passed'">background-color:lightgreen;</xsl:when>
              <xsl:otherwise>background-color:yellow;</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
          <td>
            <xsl:value-of select="@testName"/>
          </td>
          <td>
            <xsl:choose>
              <xsl:when test="@outcome = 'Failed'">FAILED</xsl:when>
              <xsl:when test="@outcome = 'Passed'">Passed</xsl:when>
              <xsl:otherwise>Inconclusive</xsl:otherwise>
            </xsl:choose>
          </td>
          <td>
            <xsl:value-of select="@duration"/>
          </td>
        </tr>
        <tr>
          <td colspan="3">
            <input type="button" class="button" onclick="return toggleMe('{$executionId}')" value="Show Details" />
            <div style="display:none" id="{$executionId}">
              <table style="width:700;border:1px solid black;font-family:Verdana; font-size:10pt;">
                <tr>
                  <td colspan="3">
                    <table style="width:700;border:1px solid black;font-family:Verdana; font-size:8pt;table-layout:fixed;">
                      <tr>
                        <td width="10"></td>
                      </tr>
                      <tr>
                        <td width="10"></td>
                        <td>
                          <pre style="word-wrap: break-word">
                            <xsl:value-of select="vs:Output/vs:StdOut"/>
                          </pre>
                        </td>
                      </tr>
                      <tr>
                        <td width="10"></td>
                        <td>
                          <pre style="word-wrap: break-word">
                            <xsl:value-of select="vs:Output/vs:DebugTrace"/>
                          </pre>
                        </td>
                      </tr>
                      <tr>
                        <td width="10"></td>
                        <td>
                          <pre style="word-wrap: break-word">
                            <xsl:value-of select="vs:Output/vs:ErrorInfo/vs:Message"/>
                          </pre>
                        </td>
                      </tr>
                      <tr>
                        <td width="10"></td>
                        <td>
                          <pre style="word-wrap: break-word">
                            <xsl:value-of select="vs:Output/vs:ErrorInfo/vs:StackTrace"/>
                          </pre>
                        </td>
                      </tr>
                    </table>
                  </td>
                </tr>
              </table>
            </div>
          </td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

You can convert this programatically using the class below, call it like this:

TrxConverter.Transform(xsltFile, trxFilePathName, htmlFilePathName);

public static class TrxConverter
    {
        public static XslCompiledTransform LoadXsl(string xsltPath)
        {
            var transform = new XslCompiledTransform();
            var settings = new XmlReaderSettings();
            settings.ProhibitDtd = false;
            using (XmlReader reader = XmlReader.Create(xsltPath, settings))
            {
                var xsltSettings = new XsltSettings();
                xsltSettings.EnableDocumentFunction = true;
                transform.Load(reader, xsltSettings, new XmlUrlResolver());
            }
            return transform;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="input">The input .trx file</param>
        /// <param name="output">The output .html file</param>
        public static void Transform(string xsltPath, string input, string output)
        {
            XslCompiledTransform transform = LoadXsl(xsltPath);
            var writerSettings = new XmlWriterSettings();
            writerSettings.ConformanceLevel = ConformanceLevel.Auto;

            using (XmlWriter writer = XmlWriter.Create(output, writerSettings))
            {
                var arguments = new XsltArgumentList();
                //arguments.AddParam("html.stylesheet", String.Empty, "styles.css");
                transform.Transform(CreateReader(input), arguments, writer);
            }
        }

        public static XmlReader CreateReader(string pathToTrxFile)
        {
            XmlReaderSettings readerSettings = new XmlReaderSettings();
            readerSettings.ProhibitDtd = false;
            return XmlReader.Create(pathToTrxFile, readerSettings);
        }
    }