0

I am trying to check the elements of an xml file I generate. I use Fluent Assertions and I am sure there must be a way to assert that "this element exists in the document" by providing only one argument.

For testing purposes, I need to know if some elements are still present or not.

I know I can compare the file with an existing one. Thing is, I know my xml file is not going to be consistent, some elements might be moved or some of their arguments can change. But not all of them.

Let's say this is my xml file:

<tools>
    <tool name="AA" description="AhAh">5</tool>
    <tool name="BB" description="BBBB" detail="Bexample">15</tool>
    <tool name="CC">12</tool>
</tools>

I know the element with name "BB" is not going to be removed in the future I would like to check it this way:

var tools = xml.XPathSelectElements(".//tools//tool");
var containedElement = new XElement("tools")
                new XElement("tool", new XAttribute("name", "BB")));

//Here is what I have tried so far
using (new AssertionScope())
{
     tools.Should().HaveElement("tool").Which.Should().HaveAttribute("name", "BB");
     tools.Should().BeEquivalentTo(containedElement);
     tools.Should().ContainEquivalentOf(containedElement);
}

But it seems I cannot check an element without specifying its position in the node if another element before him has the same Element Name.

Message: Expected attribute "name" at "/tool" to have value "BB", but found "AA".

Does anyone has an idea to solve this problem? Thanks for the help

vvilin
  • 185
  • 10

2 Answers2

0

Instead of trying to force the framework to do something it can't, consider another approach

var xml = @"
<tools>
    <tool name=""AA"" description=""AhAh"">5</tool>
    <tool name=""BB"" description=""BBBB"" detail=""Bexample"">15</tool>
    <tool name=""CC"">12</tool>
</tools>";

XElement tools = XElement.Parse(xml); //For demonstration purposes only

XElement expected = XElement.Parse(@"<tool name=""BB"" description=""BBBB"" detail=""Bexample"">15</tool>");

tools.Elements()
    .FirstOrDefault(e => e.Attributes("name").Any(a => a.Value == "BB"))
    .Should().NotBeNull()
    .And.BeEquivalentTo(expected);

The above example tries to find the desired element and then do the assertions on that

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Thank you for the fast answer. I have read the fluent assertion documentation, I want to be sure I am not missing something. Thing is, I don't want to have to compare the other attributes (description and detail) because I don't have to know if they will be present in the future. I guess my solution will be to fetch the xml file, remove the attributes and elements I am not interested in, and eventually compare with elements that only contain name attributes. – vvilin Sep 11 '19 at 16:20
0

Maybe you could user more XPath

 var bbTool = xml.XPathSelectElements(".//tools//tool[@name='BB']").FirstOrDefault();
 bbTool.Should().NotBeNull("was expected to find an element `tool` with attribute `name` and value `BB`");

In case of null, you'll get the following:

"Message: Expected bbTool not to be <null> because was expected to find an element `tool` with attribute `name` and value `BB`."
Adrian Iftode
  • 15,465
  • 4
  • 48
  • 73
  • This works but in case of error this is not really helping. While I would get "Object was expected to be not null"with your solution I am looking for something giving me something like, "attribute name was expected to be BB but foo was found instead" Thank you for the answer tho – vvilin Sep 26 '19 at 23:20
  • 1
    Made the edit. Slightly better, but I know what you mean. Would have been nice to have something like xml.Should().HaveElement(xpath) and in case of an error to translate the xpath in something friendly so it can be created an explanatory error message – Adrian Iftode Sep 26 '19 at 23:37