группировка тестов на основе класса в отчете mstest с использованием xsl

Я пишу xslt для trx-файла mstest.
Помимо информации о результатах всего сеанса, я также хотел бы знать количество успешных и неудачных попыток для каждого класса.
Я пытался разными способами, но я не могу получить результаты для определенного класса.
Вот как выглядит xml.

(редактировать)

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

Вот образец требуемого вывода.


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

Я получаю атрибут className из //UnitTest/TestMethod, получаю соответствующий id из //UnitTest, а затем сопоставляю его с //UnitTestResult[@testId], чтобы получить соответствующее значение атрибута outcome. Но я не могу выполнить свое требование. Не знаю, где я ошибаюсь.
В этом примере только 1 класс. но в самом файле, над которым я работаю, много классов.

Заранее спасибо.

(edit2) Вот часть xsl, которую я сейчас использую.

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

Извините за огромный ввод кода. Но на самом деле я использую javascript, чтобы скользить по именам тестов при нажатии на определенный класс. Так что мне нужно так много шаблонов. Я что-то пропустил в коде..


person Sidd    schedule 23.06.2010    source источник
comment
Если вы действительно хотите, чтобы кто-то ответил, вам нужно предоставить очень простой пример (не более 20 строк), а также предоставить желаемый результат.   -  person Dimitre Novatchev    schedule 24.06.2010
comment
Я могу представить, читая ваше объяснение, что эту задачу можно легко выполнить с помощью ключей (так как здесь есть перекрестные ссылки). Если бы вы могли привести небольшой пример структуры входного документа (без атрибутов, которые не нужны для этого преобразования , например) и пример выходного документа, мы можем дать вам пример полной таблицы стилей.   -  person    schedule 24.06.2010
comment
Я отредактировал вопрос с образцом ввода и образцом вывода. Я пробовал использовать ключи. Но, возможно, я использовал их неправильно. Ваша помощь очень ценится. Большое спасибо.   -  person Sidd    schedule 24.06.2010
comment
Я не могу отладить неполную таблицу стилей...   -  person    schedule 26.06.2010
comment
Также обратите внимание, что мои таблицы стилей дают желаемый результат, который вы публикуете. Один с первым входным документом, другой с вашим входным документом сокращения. Итак, это должно быть помечено как подтвержденное. Вы можете запросить другой желаемый результат, и мы, конечно же, поможем вам с другой таблицей стилей. Или вы можете попросить кого-нибудь отладить вашу таблицу стилей, но вы должны предоставить полную.   -  person    schedule 26.06.2010


Ответы (2)


Эта таблица стилей:

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

Результат:

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

Примечание: метод Мюнха для получения каждого className (я делал это в template/@match, но сегодня кажется, что не могу!) и использование набора узлов для key() второго аргумента. Редактировать: я понял! Кажется, я недостаточно знал о шаблонах, встроенных шаблонах и приоритетах...

Edit2: для первого входного документа.

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

Вам нужны небольшие модификации. С этой таблицей стилей:

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

Вы получаете этот результат:

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

Примечание. Использование пространства имен в шаблонах (ваш первый входной документ имеет пространство имен по умолчанию, но не ваш второй образец). Я нашел ваши данные о продолжительности в вашем первом вводе. Вы должны фильтровать текстовые узлы (в вашем первом вводе не было ни одного)

person Community    schedule 25.06.2010
comment
@Алехандро: Спасибо. Это очень полезно. Но ключи, похоже, ничего мне не возвращают. Не могли бы вы сказать мне, что именно это делает? TestMethod[count(.|key('class',@className)[1])=1] - person Sidd; 25.06.2010
comment
@Sidd: Вы выполнили это преобразование? Каков был результат? TestMethod[count(.|key('class',@className)[1])=1] означает: элемент TestMethod, для которого возвращается единица в результате подсчета объединения самого себя с первым элементом TestMethod, значение ключа которого равно атрибуту className данного элемента. Другими словами: первый TestMethod с таким значением ключа. - person ; 25.06.2010
comment
@Alejandro: у меня были 0 во всех столбцах. Я попытался изменить пространства имен для элементов и до сих пор не могу получить правильные числа. - person Sidd; 25.06.2010
comment
Я внес эти изменения в свой файл. Шаблон не применяется, когда я использую ‹xsl:apply-templates /›. Но он вызывается в ‹xsl:call-template›. Но даже тогда значения равны 0. Я пропустил что-то тривиальное? - person Sidd; 26.06.2010
comment
@Sidd: я запускал свои таблицы стилей с каждым входным документом (тот, который вы публикуете раньше, и сокращенный) и получаю точный результат. Вы запускали эти таблицы стилей с этими входными документами? Каковы результаты? Если вы используете эти таблицы стилей для другого входного документа, опубликуйте их повторно. Я не гадалка... - person ; 26.06.2010
comment
Я запустил таблицы стилей для одного и того же входного документа. Я отредактировал вопрос с частью таблицы стилей, которую я фактически использую. - person Sidd; 26.06.2010
comment
@Sidd: Также обратите внимание, что мои таблицы стилей дают желаемый результат, который вы публикуете. Один с первым входным документом, другой с вашим входным документом сокращения. Итак, это должно быть помечено как подтвержденное. Вы можете запросить другой желаемый результат, и мы, конечно же, поможем вам с другой таблицей стилей. Или вы можете попросить кого-нибудь отладить вашу таблицу стилей, но вы должны предоставить полную. - person ; 26.06.2010

Не зная точного вывода, который вы хотите, следующая таблица стилей соответствует описанным критериям:

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

и генерирует следующий образец вывода:

<?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>
person Mads Hansen    schedule 24.06.2010
comment
Мне жаль. Я хочу рассчитать количество пройденных и неудачных тестов для каждого класса. Мой окончательный вывод отображает классы списка с соответствующим количеством пройденных и не пройденных тестов. Щелкнув по классу, вы получите дополнительную информацию о тестах. - person Sidd; 24.06.2010