简体   繁体   中英

How does one unit test modifying an XML document?

I'm at a loss for how to even begin creating unit tests for this method:

public override void ModifyXmlDocument(Foo foo, string nodeToChange, string newValue)
{
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.Load(foo.XmlPathAndFileName);
    XmlElement rootElement = xmlDocument.DocumentElement;
    // rest of method (to modify an XML doc) here
}

That method simply finds the element/node in an XML doc and updates it with the user-supplied value. (The method is more complex than what is shown here.)

The part that I'm having a hard time with is understanding how to have this method execute, without relying on the hard disk. But xmlDocument.Load() takes a file path and loads a file from disk. At the end of the method, it saves the updated file back to disk.

How can I make this method unit testable?

There are a couple of ways you can do this, but all require a refactoring of your code. ModifyXmlDocument will need to take XmlDocument as a parameter, then you can mock it from there on.

public void test_that_xml_is_loaded()
{
    var sut = new SUT();
    var xmldocumentfake = new Mock<XmlDocument>(){CallBase=true};
    xmldocumentfake.Setup(x=>x.LoadXml(It.IsAny<String>()));

    sut.ModifyXmlDocument(foo, nodeToChange, newValue, xmlDocumentfake.Object);

   xmldocumentfake.Verify(x=>x.LoadXml(It.IsAny<String>()), Times.Once());
}

You could also wrap the XmlDocument in another class that you can write as an abstraction that can be modified. Again, you would have to pass it in, though.

Also, as Anthony Pegram had alluded and what I mean: be careful that you are not breaking the Single Responsibility Principle . When tests are too hard to write, that is often a scream that you have broken that principle.

A couple of options:

  • If you are using VS2012 Ultimate, you can use the Fakes to create a shim that will override the behavior when XmlDocument opens the file.
  • When you are testing, deploy a sample XML file with your unit tests. Then when passing in a Foo instance, use the path to that file.
  • Try one of the alternates to XmlDocument.Load such as one that takes a stream or XmlReader. Then create that with a method that you can override.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM