Parse Fitnesse RESTFul вывод XML в формат TFS Test - PullRequest
6 голосов
/ 23 октября 2009

Я интегрирую тестовый набор Fitnesse Acceptance в процесс CI на основе TFS.

Я могу запустить комплект тестов Fitnesse RESTful (http://fitnesse.org/FitNesse.UserGuide.RestfulTests):

http://myfitnesseserver/MyTestSuite?suite&format=xml

и получите XML-документ с результатами теста.

Я хотел бы преобразовать это в формат, который TFS может интерпретировать как количество пройденных / не пройденных тестов.

Есть указатели?

Спасибо

Ответы [ 3 ]

7 голосов
/ 02 ноября 2009

У меня похожая цель в работе, поэтому я создал универсальный тестовый прогон Fitnesse для командной строки, который выполняет тест или набор в виде веб-запроса, анализирует полученный XML-код и преобразует его, используя таблицу стилей ниже, и, наконец, записывает результат в файл с именем "results.xml" в% TestOutputDirectory%, как указано в универсальном тесте в Visual Studio.

Файл результатов загружается Visual Studio и анализируется как файл итоговых результатов , который сообщает о количестве дочерних тестов, которые пройдены или не пройдены в тесте или наборе Fitnesse. Подробная информация о формате выходного файла задокументирована здесь , но простой пример выглядит следующим образом при запуске с двухминутным примером Fitnesse в вики по умолчанию Fitnesse:

<?xml version="1.0" encoding="utf-8"?>
<SummaryResult>
  <TestName>TwoMinuteExample</TestName>
  <TestResult>Failed</TestResult>
  <ErrorMessage>6 right, 1 wrong, 0 ignores and 0 exceptions.</ErrorMessage>
  <InnerTests>
    <InnerTest>
      <TestName>TwoMinuteExample</TestName>
      <TestResult>Failed</TestResult>
      <ErrorMessage>6 right, 1 wrong, 0 ignores and 0 exceptions.</ErrorMessage>
    </InnerTest>
  </InnerTests>
</SummaryResult>

Таким образом, теперь можно создавать «универсальный тест» Visual Studio в тестовом проекте для каждого теста / набора Fitnesse, который вы хотите выполнить из Visual Studio или как часть сборки. Универсальный тест должен указывать путь к исполняемому файлу универсального тестового прогона, серверу Fitnesse, порту и имени теста / набора в вики. Требуется установить флажок для «файла итоговых результатов» и ввести «Results.xml», чтобы получить подробности, которые будут отображаться в результатах выполнения теста или сборки.

Я могу поделиться этим кодом с вами, или вы можете использовать универсальный тестовый запуск командной строки и направить вывод в небольшое приложение, которое преобразует результаты, используя таблицу стилей ниже.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="msxsl"
    >
  <xsl:output method="xml" indent="yes"/>

  <xsl:variable name="GlobalRightCount" select="sum(//result/counts/right)"/>
  <xsl:variable name="GlobalIgnoresCount" select="sum(//result/counts/ignores)"/>
  <xsl:variable name="GlobalWrongCount" select="sum(//result/counts/wrong)"/>
  <xsl:variable name="GlobalExceptionsCount" select="sum(//result/counts/exceptions)"/>
  <xsl:variable name="GlobalFailureCount" select="$GlobalWrongCount + $GlobalExceptionsCount"/>

  <xsl:template match="testResults">
    <SummaryResult>
      <TestName>
        <xsl:value-of select="rootPath"/>
      </TestName>
      <xsl:choose>
        <xsl:when test="$GlobalFailureCount = 0">
          <TestResult>Passed</TestResult>
          <xsl:call-template name="GlobalErrorMessage"/>
        </xsl:when>
        <xsl:otherwise>
          <TestResult>Failed</TestResult>
          <xsl:call-template name="GlobalErrorMessage"/>
        </xsl:otherwise>
      </xsl:choose>
      <InnerTests>
        <xsl:for-each select="result">
          <InnerTest>
            <TestName>
              <xsl:value-of select="relativePageName"/>
            </TestName>
            <xsl:choose>
              <xsl:when test="sum(counts/wrong) + sum(counts/exceptions) = 0">
                <TestResult>Passed</TestResult>
                <xsl:call-template name="ResultErrorMessage"/>
              </xsl:when>
              <xsl:otherwise>
                <TestResult>Failed</TestResult>
                <xsl:call-template name="ResultErrorMessage"/>
              </xsl:otherwise>
            </xsl:choose>
          </InnerTest>
        </xsl:for-each>
      </InnerTests>
    </SummaryResult>
  </xsl:template>


  <xsl:template name="GlobalErrorMessage">
    <ErrorMessage><xsl:value-of select ="$GlobalRightCount"/> right, <xsl:value-of select ="$GlobalWrongCount"/> wrong, <xsl:value-of select ="$GlobalIgnoresCount"/> ignores and <xsl:value-of select ="$GlobalExceptionsCount"/> exceptions.</ErrorMessage>
  </xsl:template>

  <xsl:template name="ResultErrorMessage">
    <ErrorMessage><xsl:value-of select ="sum(counts/right)"/> right, <xsl:value-of select ="sum(counts/wrong)"/> wrong, <xsl:value-of select ="sum(counts/ignores)"/> ignores and <xsl:value-of select ="sum(counts/exceptions)"/> exceptions.</ErrorMessage>
  </xsl:template>
</xsl:stylesheet>

Обновление: добавление общего кода участника теста

Это определенно просто подтверждение концепции, а не обязательно окончательное решение. Возможно, вы сможете объединить эту технику с ответом Мартина Вудворда, чтобы получить полную картину, где сам список тестов является динамическим. Или вы можете изменить тестировщика так, чтобы он выполнял все тесты, которые он находит во всей (под) вики. Здесь, возможно, есть несколько других вариантов.

Следующий код далеко не оптимизирован, но показывает общий процесс. Вы можете вставить это в новый проект консольного приложения. Обратите внимание, что для этого требуются параметры командной строки, и вы можете указать их по умолчанию в свойствах проекта:

Пример командной строки: localhost 80 FitNesse.UserGuide.TwoMinuteExample

class Program
{
    static int Main(string[] args)
    {
        //Default to error unless proven otherwise
        int returnValue = 1; 

        try
        {
            List<string> commandLineArgs = args.ToList<string>();

            string host = args[0];
            int port = int.Parse(args[1]);
            string path = args[2];
            string testCommand = "suite";

            XmlDocument fitnesseResults = GetFitnesseResult(host, port, path, testCommand);
            XmlDocument visualStudioResults = TransformFitnesseToVisualStudioResults(fitnesseResults);
            visualStudioResults.Save("Results.xml");

            var testResultNode = visualStudioResults.DocumentElement.SelectSingleNode("TestResult");
            var value = testResultNode.InnerText;
            if (value == "Success")
            {
                returnValue = 0;
            }
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        return returnValue;
    }

    private static XmlDocument GetFitnesseResult(string host, int port, string path, string testCommand)
    {
        UriBuilder uriBuilder = new UriBuilder("http", host, port, path, "?" + testCommand + "&format=xml");
        WebRequest request = HttpWebRequest.Create(uriBuilder.Uri);
        request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);

        WebResponse response = request.GetResponse();
        Stream responseStream = response.GetResponseStream();
        StreamReader responseReader = new StreamReader(responseStream);
        string responseString = responseReader.ReadToEnd();

        XmlDocument rawResults = new XmlDocument();
        rawResults.LoadXml(responseString);

        return (rawResults);
    }

    private static XmlDocument TransformFitnesseToVisualStudioResults(XmlDocument fitnesseResults)
    {
        XslCompiledTransform transformer = new XslCompiledTransform(false);
        string codeBase = Assembly.GetEntryAssembly().CodeBase;
        string directory = Path.GetDirectoryName(codeBase);
        string xsltPath = Path.Combine(directory, "FitnesseToSummaryResult.xslt");
        transformer.Load(xsltPath);

        MemoryStream resultsStream = new MemoryStream();
        transformer.Transform(fitnesseResults, null, resultsStream);
        resultsStream.Position = 0;
        XmlDocument results = new XmlDocument();
        results.Load(resultsStream);

        return (results);
    }
}
0 голосов
/ 06 ноября 2009

@ Джерри, эт. и др.

Вы столкнулись с этой проблемой? Я выполняю код, очень похожий на описанный выше, когда в режиме nUnitTest и URI содержит «/? Test & format = xml», тест nUnit завершается неудачно с IOException, «Невозможно прочитать данные из транспортного соединения: соединение закрыто».

Однако трассировка Fiddler, которая была запущена в то время, показывает тот самый xml, который я ожидал.

Я воссоздаю заголовки запросов точно (почти) так, как они отправляются при отправке через браузер.

Наконец, если я пропущу "/? Test & format = xml" из URI, я получу HTML, который в противном случае ожидал бы.

Заинтригованный? У меня есть исходный код ...:)

0 голосов
/ 26 октября 2009

Формат файла TRX на 2008 год довольно прост в создании, но не слишком хорошо документирован. Он содержит кучу GUIDS - лучшая документация для этого в этом блоге:

Я написал некоторый код, который будет принимать вывод из JUnit и преобразовывать его в файл TRX. Он фактически делает это в два этапа - первый объединяет все файлы результатов JUnit в единый файл и генерирует необходимые GUIDS, необходимые для файла TRX. Затем он запускает XSLT для объединенного XML-файла, чтобы преобразовать его в формат файла TRX перед публикацией в TFS с помощью инструмента командной строки MSTest.exe, который поставляется с редакцией Team Visual Studio (Team Suite, Developer или Test). 1009 *

Вы можете скачать этот код здесь под лицензией MSPL

...