【问题标题】:Parse Fitnesse RESTFul XML output into TFS Test format将 Fitnesse RESTFul XML 输出解析为 TFS 测试格式
【发布时间】:2010-12-09 12:35:44
【问题描述】:

我正在将 Fitnesse 验收测试套件集成到基于 TFS 的 CI 流程中。

我可以以 RESTful 方式运行 Fitnesse 测试套件 (http://fitnesse.org/FitNesse.UserGuide.RestfulTests):

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

并取回测试结果的 XML 文档。

我想将其转换为 TFS 可以解释为通过/失败的测试数量的格式。

任何指针?

谢谢

【问题讨论】:

    标签: tfs automated-tests mstest tfsbuild fitnesse


    【解决方案1】:

    我在工作中也有类似的目标,所以我创建了一个通用的命令行 Fitnesse 测试运行器,它以 Web 请求的形式执行测试或套件,解析生成的 XML 并使用下面的样式表对其进行转换,最后编写结果到 %TestOutputDirectory% 中名为“results.xml”的文件中,由 Visual Studio 中的通用测试指定。

    结果文件由 Visual Studio 加载并解析为 summary results file,报告在 Fitnesse 测试或套件中通过或失败的子测试数量。输出文件格式的详细信息记录在 here 中,但是当在默认的 Fitnesse wiki 中针对 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 服务器、端口和 wiki 中的测试/套件名称。它需要选中“摘要结果文件”复选框并输入“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>
    

    更新:添加通用测试运行程序代码

    这绝对只​​是概念验证,不一定是最终解决方案。您可以将此技术与 Martin Woodward 的答案结合起来,以获得测试列表本身是动态的完整图片。或者,您可以更改测试运行程序以运行它在整个(子)wiki 中找到的所有测试。这里可能还有其他几个选项。

    以下代码远未优化,但显示了一般过程。您可以将其粘贴到新的控制台应用程序项目中。请注意,它需要命令行参数,您可以在项目属性中为这些参数提供默认值:

    命令行示例: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);
        }
    }
    

    【讨论】:

    • @Jerry - 这几乎正是我的想法,如果你想要你的 TFS“测试计数”,你必须为每个 Fitnesse 测试指定许多“映射”通用测试。要增加的数字:) 您能否发布通用测试运行程序可执行文件的代码;然后,我将与我调用 Fitnesse 的 MSBuild 目标方法进行比较,并发布与此问题最相关的解决方案。 PS:我想把赏金分配给你;但我找不到按钮。 Grr.
    • 添加了通用测试运行器的源代码。它需要样式表位于名为 FitnesseToSummaryResult.xslt 的文件中,并设置为复制到输出目录。
    【解决方案2】:

    2008 年的 TRX 文件格式相当容易生成,但文档并没有过多完善。它包含一堆 GUIDS - 最好的文档在这篇博文中:

    我编写了一些代码,这些代码将从 JUnit 获取输出并将其转换为 TRX 文件。它实际上分两步完成——第一步将所有 JUnit 结果文件合并到一个文件中,并生成 TRX 文件所需的必要 GUIDS。然后,它在合并的 XML 文件上运行 XSLT,以将其转换为 TRX 文件格式,然后使用 Visual Studio 团队版(团队套件、开发人员或测试版)附带的 MSTest.exe 命令行工具发布到 TFS。

    您可以在此处根据 MSPL 许可证下载该代码

    【讨论】:

      【解决方案3】:

      @Jerry 等。人。

      你遇到过这个问题吗?我运行的代码与上面的代码非常相似,当处于 nUnitTest 模式并且 URI 包含“/?test&format=xml”时,nUnit 测试失败并出现 IOException,“无法从传输连接读取数据:连接已关闭。”

      但是,当时运行的 Fiddler 跟踪显示的正是我所期望的 xml。

      我已经完全(几乎)重新创建了请求标头,就像它们通过浏览器发送时一样。

      最后,如果我从 URI 中去掉“/?test&format=xml”,我会得到原本预期的 html。

      感兴趣?我有源代码... :)

      【讨论】:

      • @Michael,您运行的是最新版本的 Fitnesse 吗?我注意到 RESTful 测试方法(即 &format=xml)调用一直在稳步发展并消除错误。
      • @David,实际上,我们是。我通过从 HTML 中解析结果来管理解决方法,但我认为问题在于 http 响应编码被分块。自从我们转向更大更好的事情后,我没有进一步调查,但你重新点燃了我的好奇心。 ;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多