开发者

grouping tests based on class in mstest report using xsl

开发者 https://www.devze.com 2023-01-04 08:09 出处:网络
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'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&开发者_如何学JAVAgt;
    <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..


This stylesheet:

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

    <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">
    <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)


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">
<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">
    <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>
0

精彩评论

暂无评论...
验证码 换一张
取 消