tags:

views:

62

answers:

2

I'm writing an xslt for the trx file of mstest.
Apart from knowing the results of the entire session, I'd also like to know the number of successes and failures for each class.
I've tried out many ways, but i'm not able to get the results for a particular class.
This is how the xml looks.

(edit)

<TestRun>
 <ResultSummary outcome="Completed">
  <Counters total="2" passed="2" error="0" failed="0" inconclusive="0" /> 
 </ResultSummary>
 <TestDefinitions>
  <UnitTest name="NullUserIdInConstructor" id="e58f837c-2116-ce69-bf31-1fe6beec73d3"> 
   <TestMethod className="TestProject1.Test.LogonInfoTest, TestProject1.Test" name="NullUserIdInConstructor" /> 
  </UnitTest>
  <UnitTest name="LogonInfoConstructorTest" id="b9bbb3b6-cc0b-7f4d-276e-16c52b0814c6">
   <TestMethod className="TestProject1.Test.LogonInfoTest, TestProject1.Test" name="LogonInfoConstructorTest" /> 
  </UnitTest>
 </TestDefinitions>
 <Results>
  <UnitTestResult testId="b9bbb3b6-cc0b-7f4d-276e-16c52b0814c6" testName="LogonInfoConstructorTest" outcome="Passed" >
 </UnitTestResult>
 <UnitTestResult testId="e58f837c-2116-ce69-bf31-1fe6beec73d3" testName="NullUserIdInConstructor"  outcome="Passed" >
 </UnitTestResult>
</Results>
</TestRun>

Here's a sample of the required output.


    <table>
      <tr>
         <td>Test Name</td>
         <td>Result</td>
         <td>Duration</td>
         <td>Passed</td>
         <td>Failed</td>
         <td>Inconclusive</td>
      </tr>
      <tr>
        <td colspan="3">This is the Class Name</td>
 <td>2</td>
 <td>0</td>
 <td>0</td>
      </tr>
      <tr>
        <td>LogonInfoConstructorTest</td>
        <td>Passed</td>
        <td>00:00:00.0234997</td>
      </tr>
      <tr>
        <td>NullUserIdInConstructor</td>
        <td>Passed</td>
        <td>00:00:00.0047344</td>
      </tr>
    </table>

I'm getting the className attribute from //UnitTest/TestMethod, getting the correspoding id from //UnitTest and then matching it with //UnitTestResult[@testId] to get the corresponding value of the outcome attribute. But I'm not able to accomplish my requirement. I'm not sure where I'm going wrong.
This sample has only 1 class. but the actual file I'm working on has many classes.

Thanks in advance.

(edit2) Here's a part of the xsl I'm currently using.

  <xsl:key name="class-key" match="@className" use="."/>
  <xsl:key name="class" match="t:TestMethod" use="@className"/>
  <xsl:key name="result" match="t:UnitTestResult" use="@testName"/>

  <xsl:variable name="unique-classes" select="//t:TestMethod/@className[generate-id(.)=generate-id(key('class-key',.))]" />

  <xsl:template name="details2">
    <h3>Unit Test Results</h3>
    <table>
  <tr>
    <td></td>
    <td>Test Name</td>
    <td>Result</td>
    <td>Duration</td>
  </tr>

  <xsl:for-each select="$unique-classes">
    <xsl:sort />
    <xsl:variable name="curClass" select="."/>

    <xsl:variable name="parentId" select="generate-id(./..)" />
    <xsl:variable name="currentId" select="generate-id(.)" />
    <tr id="{$parentId}">
      <td id="{$currentId}"
          style="font-weight:bold; cursor:pointer;"
          onClick="toggleDetail(this)">[+]</td>

      <xsl:call-template name="groups" />
      </tr>

          <xsl:call-template name="classRunsDetail">
            <xsl:with-param name="curClass" select="."/>
          </xsl:call-template>

    <tr id="{$currentId}-end" style="display:none;">
      <td style="border-bottom:0px solid black;height:1px;background-color:black" colspan="4"></td>
    </tr>
  </xsl:for-each>
</table>
  </xsl:template>


  <xsl:template name="classRunsDetail">
    <xsl:param name="curClass"/>
    <xsl:variable name="parentId" select="generate-id(.)" />

<xsl:for-each select="//t:UnitTest/t:TestMethod[@className=$curClass]">
  <xsl:sort select="@name"/>
  <xsl:variable name="testid" select="../@id"/>
  <xsl:for-each select="//t:UnitTestResult[@testId=$testid]">
<tr id="{$parentId}">
  <td></td>
  <td>
    <xsl:value-of select="@testName"/>
  </td>
  <td>
    <xsl:choose>
      <xsl:when test="@outcome = $fail">FAILED</xsl:when>
      <xsl:when test="@outcome = $pass">Passed</xsl:when>
      <xsl:when test="@outcome = $incon">Not Run</xsl:when>
      <xsl:otherwise>Error</xsl:otherwise>
    </xsl:choose>
  </td>
  <td>
    <xsl:value-of select="@duration"/>
  </td>
</tr>
  </xsl:for-each>
</xsl:for-each>
  </xsl:template>

  <xsl:template name="groups" match="t:TestMethod[count(.|key('class',@className)[1])=1]">
    <xsl:variable name="result" select="key('result',key('class',@className)/@name)"/>
      <td valign="bottom" style="background-color:beige;font-weight:bold;" colspan="3">
    <xsl:value-of select="key('class', @className)[1]"/>
  </td>
  <td>
    <xsl:value-of select="count($result[@outcome='Passed'])"/>
  </td>
  <td>
    <xsl:value-of select="count($result[@outcome='Failed'])"/>
  </td>
  <td>
    <xsl:value-of select="count($result[@outcome='Inconclusive'])"/>
  </td>
<xsl:apply-templates select="key('class',@className)" mode="sub"/>
  </xsl:template>

Sorry for the huge code input. But I'm actually using javascript to slide down the test names when a particular class is clicked. So I need so many templates. Am I missing something in the code..

A: 

Not knowing the exact output you want, the following stylesheet matches the described criteria:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tt="http://microsoft.com/schemas/VisualStudio/TeamTest/2006"&gt;
<xsl:output method="xml" indent="yes" />
    <xsl:template match="/">
        <tests>
            <xsl:apply-templates select="//tt:UnitTest"/>
        </tests>
    </xsl:template>

    <xsl:template match="tt:UnitTest">
        <xsl:variable name="id" select="@id" />
        <test>
            <className>
                <xsl:value-of select="tt:TestMethod/@className"/>
            </className>
            <outcome>
                <xsl:value-of select="//tt:UnitTestResult[@testId=$id]/@outcome"/>
            </outcome>
        </test>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

and generates the following sample output:

<?xml version="1.0" encoding="UTF-8"?>
<tests xmlns:tt="http://microsoft.com/schemas/VisualStudio/TeamTest/2006"&gt;
    <test>
        <className>TestProject1.Test.LogonInfoTest, TestProject1.Test</className>
        <outcome>Passed</outcome>
    </test>
    <test>
        <className>TestProject1.Test.LogonInfoTest, TestProject1.Test</className>
        <outcome>Passed</outcome>
    </test>
    <test>
        <className>TestProject1.Test.LogonInfoTest, TestProject1.Test</className>
        <outcome>Passed</outcome>
    </test>
</tests>
Mads Hansen
I'm sorry. I want to calculate the number of passed and failed tests for each class. My final output displays a list classes with the correspoding number of passed and failed tests. Clicking the class would give further details of the tests.
Sidd
A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt; 

    <xsl:output indent="yes"/>
    <xsl:key name="class" match="TestMethod" use="@className"/>
    <xsl:key name="result" match="UnitTestResult" use="@testName"/>

    <xsl:template match="/">
    <table>
      <tr>
         <td>Test Name</td>
         <td>Result</td>
         <td>Duration</td>
         <td>Passed</td>
         <td>Failed</td>
         <td>Inconclusive</td>
      </tr>
      <xsl:apply-templates/>
    </table>
    </xsl:template>

    <xsl:template match="TestMethod[count(.|key('class',@className)[1])=1]">
      <xsl:variable name="result" select="key('result',key('class',@className)/@name)"/>
      <tr>
        <td colspan="3"><xsl:value-of select="@className"/></td>
        <td><xsl:value-of select="count($result[@outcome='Passed'])"/></td>
        <td><xsl:value-of select="count($result[@outcome='Failed'])"/></td>
        <td><xsl:value-of select="count($result[@outcome='Inconclusive'])"/></td>
      </tr>
      <xsl:apply-templates select="key('class',@className)" mode="sub"/>
    </xsl:template>

    <xsl:template match="TestMethod" mode="sub">
      <tr>
        <td><xsl:value-of select="@name"/></td>
        <td><xsl:value-of select="key('result',@name)/@outcome"/></td>
        <td>Not in sample</td>
      </tr>
    </xsl:template> 

</xsl:stylesheet> 

Result:

<table>
<tr>
<td>Test Name</td>
<td>Result</td>
<td>Duration</td>
<td>Passed</td>
<td>Failed</td>
<td>Inconclusive</td>
</tr>
<tr>
<td colspan="3">TestProject1.Test.LogonInfoTest, TestProject1.Test</td>
<td>2</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>NullUserIdInConstructor</td>
<td>Passed</td>
<td>Not in sample</td>
</tr>
<tr>
<td>LogonInfoConstructorTest</td>
<td>Passed</td>
<td>Not in sample</td>
</tr>
</table>

Note: Muenchian method for get each className (I used to do that in template/@match but today it seems that I can't!) and the use of a node-set for key() second argument. Edit: I got it! It seems that I didn't know enough about patterns, built-in templates and priority...

Edit2: For the first input document

<TestRun id="41242257-adae-4e41-b860-f102021e93c8" name="muthuras@SMUTHURAJA2 2010-06-09 10:13:57" runUser="AMERICAS\muthuras" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2006"&gt;
    <ResultSummary outcome="Warning">
        <Counters total="3" executed="3" passed="3" error="0" failed="0" timeout="0" aborted="0" inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" disconnected="0" warning="0" completed="0" inProgress="0" pending="0" />
        <RunInfos>
            <RunInfo computerName="SMUTHURAJA2" outcome="Warning" timestamp="2010-06-09T10:13:59.6365402-04:00">
                <Text>Code coverage instrumentation warning while processing file ClassLibrary1.dll: Warning VSP2013 : Instrumenting this image requires it to run as a 32-bit process. The CLR header flags have been updated to reflect this.</Text>
            </RunInfo>
        </RunInfos>
    </ResultSummary>
    <Times creation="2010-06-09T10:13:57.3115402-04:00" queuing="2010-06-09T10:14:00.1315402-04:00" start="2010-06-09T10:14:00.3665402-04:00" finish="2010-06-09T10:14:02.2425402-04:00" />
    <TestDefinitions>
        <UnitTest name="EmptyUserIdInConstructor" storage="c:\users\muthuras\documents\visual studio 2008\projects\classlibrary1\testproject1.test\bin\debug\testproject1.test.dll" id="eeffb9fe-2a08-9a88-c3c9-3008a9aeeb50">
            <Css projectStructure="" iteration="" />
            <Owners>
                <Owner name="" />
            </Owners>
            <Execution id="ec93c5dc-afbb-41b6-81a1-157d39286eca" />
            <TestMethod codeBase="C:\Users\muthuras\Documents\Visual Studio 2008\Projects\ClassLibrary1\TestProject1.Test\bin\Debug\TestProject1.Test.dll" adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" className="TestProject1.Test.LogonInfoTest, TestProject1.Test" name="EmptyUserIdInConstructor" />
        </UnitTest>
        <UnitTest name="NullUserIdInConstructor" storage="c:\users\muthuras\documents\visual studio 2008\projects\classlibrary1\testproject1.test\bin\debug\testproject1.test.dll" id="e58f837c-2116-ce69-bf31-1fe6beec73d3">
            <Css projectStructure="" iteration="" />
            <Owners>
                <Owner name="" />
            </Owners>
            <Execution id="4ef585f1-02e0-4eb3-b291-29fa7b02d9e6" />
            <TestMethod codeBase="C:\Users\muthuras\Documents\Visual Studio 2008\Projects\ClassLibrary1\TestProject1.Test\bin\Debug\TestProject1.Test.dll" adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" className="TestProject1.Test.LogonInfoTest, TestProject1.Test" name="NullUserIdInConstructor" />
        </UnitTest>
        <UnitTest name="LogonInfoConstructorTest" storage="c:\users\muthuras\documents\visual studio 2008\projects\classlibrary1\testproject1.test\bin\debug\testproject1.test.dll" id="b9bbb3b6-cc0b-7f4d-276e-16c52b0814c6">
            <Css projectStructure="" iteration="" />
            <Owners>
                <Owner name="" />
            </Owners>
            <Execution id="fca1597d-5011-4d16-965b-afaa9d81ee4e" />
            <TestMethod codeBase="C:\Users\muthuras\Documents\Visual Studio 2008\Projects\ClassLibrary1\TestProject1.Test\bin\Debug\TestProject1.Test.dll" adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" className="TestProject1.Test.LogonInfoTest, TestProject1.Test" name="LogonInfoConstructorTest" />
        </UnitTest>
    </TestDefinitions>
    <TestLists>
        <TestList name="Results Not in a List" id="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
        <TestList name="All Loaded Results" id="19431567-8539-422a-85d7-44ee4e166bda" />
    </TestLists>
    <TestEntries>
        <TestEntry testId="b9bbb3b6-cc0b-7f4d-276e-16c52b0814c6" executionId="fca1597d-5011-4d16-965b-afaa9d81ee4e" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
        <TestEntry testId="e58f837c-2116-ce69-bf31-1fe6beec73d3" executionId="4ef585f1-02e0-4eb3-b291-29fa7b02d9e6" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
        <TestEntry testId="eeffb9fe-2a08-9a88-c3c9-3008a9aeeb50" executionId="ec93c5dc-afbb-41b6-81a1-157d39286eca" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
    </TestEntries>
    <Results>
        <UnitTestResult executionId="fca1597d-5011-4d16-965b-afaa9d81ee4e" testId="b9bbb3b6-cc0b-7f4d-276e-16c52b0814c6" testName="LogonInfoConstructorTest" computerName="SMUTHURAJA2" duration="00:00:00.0234997" startTime="2010-06-09T10:14:00.8325402-04:00" endTime="2010-06-09T10:14:01.3215402-04:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d">
            <Output />
        </UnitTestResult>
        <UnitTestResult executionId="4ef585f1-02e0-4eb3-b291-29fa7b02d9e6" testId="e58f837c-2116-ce69-bf31-1fe6beec73d3" testName="NullUserIdInConstructor" computerName="SMUTHURAJA2" duration="00:00:00.0047344" startTime="2010-06-09T10:14:01.3235402-04:00" endTime="2010-06-09T10:14:01.3305402-04:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d">
            <Output />
        </UnitTestResult>
        <UnitTestResult executionId="ec93c5dc-afbb-41b6-81a1-157d39286eca" testId="eeffb9fe-2a08-9a88-c3c9-3008a9aeeb50" testName="EmptyUserIdInConstructor" computerName="SMUTHURAJA2" duration="00:00:00.0005633" startTime="2010-06-09T10:14:01.3315402-04:00" endTime="2010-06-09T10:14:01.3345402-04:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d">
            <Output />
        </UnitTestResult>
    </Results>
</TestRun>

You need some minor modifications. With this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:test="http://microsoft.com/schemas/VisualStudio/TeamTest/2006" exclude-result-prefixes="test">
    <xsl:output indent="yes"/>
    <xsl:key name="class" match="test:TestMethod" use="@className"/>
    <xsl:key name="result" match="test:UnitTestResult" use="@testName"/>
    <xsl:template match="text()"/>
    <xsl:template match="/">
        <table>
            <tr>
                <td>Test Name</td>
                <td>Result</td>
                <td>Duration</td>
                <td>Passed</td>
                <td>Failed</td>
                <td>Inconclusive</td>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>
    <xsl:template match="test:TestMethod[count(.|key('class',@className)[1])=1]">
        <xsl:variable name="result" select="key('result',key('class',@className)/@name)"/>
        <tr>
            <td colspan="3">
                <xsl:value-of select="@className"/>
            </td>
            <td>
                <xsl:value-of select="count($result[@outcome='Passed'])"/>
            </td>
            <td>
                <xsl:value-of select="count($result[@outcome='Failed'])"/>
            </td>
            <td>
                <xsl:value-of select="count($result[@outcome='Inconclusive'])"/>
            </td>
        </tr>
        <xsl:apply-templates select="key('class',@className)" mode="sub"/>
    </xsl:template>
    <xsl:template match="test:TestMethod" mode="sub">
        <tr>
            <td>
                <xsl:value-of select="@name"/>
            </td>
            <td>
                <xsl:value-of select="key('result',@name)/@outcome"/>
            </td>
            <td>
                <xsl:value-of select="key('result',@name)/@duration"/>
            </td>
        </tr>
    </xsl:template>
</xsl:stylesheet>

You get this result:

<table>
<tr>
<td>Test Name</td>
<td>Result</td>
<td>Duration</td>
<td>Passed</td>
<td>Failed</td>
<td>Inconclusive</td>
</tr>
<tr>
<td colspan="3">TestProject1.Test.LogonInfoTest, TestProject1.Test</td>
<td>3</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>EmptyUserIdInConstructor</td>
<td>Passed</td>
<td>00:00:00.0005633</td>
</tr>
<tr>
<td>NullUserIdInConstructor</td>
<td>Passed</td>
<td>00:00:00.0047344</td>
</tr>
<tr>
<td>LogonInfoConstructorTest</td>
<td>Passed</td>
<td>00:00:00.0234997</td>
</tr>
</table>

Note: The use of namespace in patterns (Your first input document has a default namespace, but not your second sample). I've found your duration data in your first input. You have to filter text nodes (There was not one in your first input)

Alejandro
@Alejandro: Thank you. This is very helpful. But the keys don't seem to be returning anything for me. Could you please tell me what this exactly does?TestMethod[count(.|key('class',@className)[1])=1]
Sidd
@Sidd: Did you run this transformation? What was the result? `TestMethod[count(.|key('class',@className)[1])=1]` means: An element `TestMethod` for which return one as the result of counting the union of itself with the first element `TestMethod` which has a key value equal to the attribute `className` of the given element. In oder words: the first `TestMethod` with such a key value.
Alejandro
@Alejandro: I had 0s in all my columns. I tried changing namespaces for the elements and am still not able to get the correct numbers.
Sidd
I had made these changes in my file. The template doesnt get applied when i use <xsl:apply-templates />. But it is called in <xsl:call-template>. But even then, the values are 0. Am I missing something trivial?
Sidd
@Sidd: I've run my stylesheets with each input document (the one you post early and the reduced one) and get the exact result. Did you run these stylesheets with **these** input documents? What were the results? If you are running these stylesheet against another input document, please re-post. I'm not fortune teller...
Alejandro
I ran the stylesheets against the same input document. I've edited the question with a part of the stylesheet I'm actually using.
Sidd
@Sidd: I can't debug an incomplete stylesheet...
Alejandro
@Sidd: Also note, my stylesheets produce the desired result you post. One with the first input document, another with your reduce input document. So, this must be mark as aswered. You can ask for another desired output and we will help you with another stylesheet, of course. Or you can ask for someone to debug your stylesheet, but you must provided a complete one.
Alejandro