Home > Software design >  Problem parsing through multiple elements in the XUnit XML file using XElement
Problem parsing through multiple elements in the XUnit XML file using XElement

Time:11-21

I'm having trouble using XElement to parse multiple elements through an XUnit XML file and return the value.

Here is the XML File

<assemblies timestamp="07/31/2018 14:58:48">
  <assembly name="C:\Users\bf\Documents\Visual Studio 2015\Projects\xUnitDemo\xUnitDemo\bin\Debug\xUnitDemo.DLL" environment="64-bit .NET 4.0.30319.42000 [collection-per-class, parallel (1 threads)]" test-framework="xUnit.net 2.3.1.3858" run-date="2018-07-31" run-time="14:58:47" config-file="C:\Users\bf\Documents\Visual Studio 2015\Projects\xUnitDemo\packages\xunit.runner.console.2.4.0\tools\net452\xunit.console.exe.Config" total="15" passed="14" failed="1" skipped="0" time="0.257" errors="0">
    <errors />
    <collection total="2" passed="1" failed="1" skipped="0" name="Test collection for xUnitDemo.SimpleTests" time="0.070">
      <test name="xUnitDemo.SimpleTests.PassingTest" type="xUnitDemo.SimpleTests" method="PassingTest" time="0.0636741" result="Pass">
        <traits>
          <trait name="test" value="test" />
          <trait name="requirement" value="test" />
          <trait name="labels" value="test" />
        </traits>
      </test>
      <test name="xUnitDemo.SimpleTests.FailingTest" type="xUnitDemo.SimpleTests" method="FailingTest" time="0.0059474" result="Fail">
        <failure exception-type="Xunit.Sdk.EqualException">
          <message><![CDATA[Assert.Equal() Failure\r\nExpected: 5\r\nActual: 4]]></message>
          <stack-trace><![CDATA[ at xUnitDemo.SimpleTests.FailingTest() in C:\Users\smsf\documents\visual studio 2015\Projects\xUnitDemo\xUnitDemo\SimpleTests.cs:line 30]]></stack-trace>
        </failure>
      </test>
    </collection>
  </assembly>
</assemblies>

I'm able to parse through test element using this code.

private static List<TestResults> GetTestAutomationExecutionResult(string filePath)
{
    List<TestResults> testResults = new List<TestResults>();

    XElement xelement = XElement.Load(filePath);

    IEnumerable<XElement> results = xelement.Elements().Where(e => e.Name.LocalName == "test");
    
    foreach (var result in results)
    {
        if (result.Attribute("result").Value == "Fail")
        {
            testResults.Add(new TestResults(result.Attribute("result").Value, "this is where the failure message would go"));
        }
        else
        {
            testResults.Add(new TestResults(result.Attribute("result").Value, ""));
        }
    }

But I'm having a hard time trying to find and add message inside of failure element in the foreach.

 result.Attribute("message").Value

CodePudding user response:

Your code has a couple problems:

  1. The <result> elements are not direct children of the root element, so xelement.Elements().Where(e => e.Name.LocalName == "test") does not select anything. You need to descend deeper into the hierarchy, e.g. with Descendants().

  2. The message text is contained in an indirect child element of the <test> node, specifically failure/message. You need to select this element to get the message.

    result.Attribute("message").Value will not work because the XElement.Attribute(XName) method selects an XML attribute rather than an element.

    See: XML attribute vs XML element.

Putting those two points together, your code should look like:

private static List<TestResults> GetTestAutomationExecutionResult(string filePath)
    => GetTestAutomationExecutionResult(XElement.Load(filePath));

private static List<TestResults> GetTestAutomationExecutionResult(XElement xelement)
{
    var query = from e in xelement.Descendants()
        where e.Name.LocalName == "test"
        let r = e.Attribute("result").Value
        let m = r == "Fail" ? e.Elements("failure").Elements("message").FirstOrDefault()?.Value : ""
        select new TestResults(r, m);
    return query.ToList();
}

Demo fiddle here.

  • Related