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);
}
}