7

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

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

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

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

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

任何指针?

谢谢

4

3 回答 3

9

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

结果文件由 Visual Studio 加载并解析为摘要结果文件,该文件报告在 Fitnesse 测试或套件中通过或失败的子测试数量。此处记录了输出文件格式的详细信息,但在默认 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);
    }
}
于 2009-11-02T02:34:05.487 回答
0

@杰里等。人。

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

然而,当时正在运行的 Fiddler 跟踪显示了我所期望的 xml。

我已经完全(几乎)重新创建了请求标头,因为它们是通过浏览器发送时发送的。

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

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

于 2009-11-06T00:05:43.237 回答
0

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

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

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

于 2009-10-26T15:31:17.380 回答