Recently we decided to make some updates to our web app. The front end website is in ASP.NET/C#, while the back end is all in Java and using REST APIs as the interface. One pair of programmers was assigned the task of updating the web app and the other pair was assigned the task of writing the new REST service used by the web app. To ensure that both sides would be able to talk to each other when completed, we wrote an XML Schema to act as our contract and placed it in an SVN external available to both projects.
In our functional test for the REST client side code (.NET/C#) we used a stub from which we could grab the XML being sent. To test that this XML conformed to the schema (contract) we agreed to, we created the following helper class:
Xml Validator Helper Class
using System; using System.Xml; using System.Xml.Schema; using System.IO; namespace Test.Helper { public class XmlValidatorTestHelper { private bool isValidXml = true; private string validationError = ""; public String ValidationError { get { return "Validation Error: " + validationError; } set { validationError = value; } } public bool IsValidXml { get { return isValidXml; } } /// /// Validate an xml document against an xml schema. /// public void ValidXmlDoc(XmlDocument xmlDocument, XmlSchema xmlSchema) { validateParameters(xmlDocument, xmlSchema); XmlReader xmlReader = createXmlReader(xmlDocument, xmlSchema); try { // validate using (xmlReader) { while (xmlReader.Read()) {} } isValidXml = true; } catch (Exception ex) { ValidationError = ex.Message; isValidXml = false; } } private static void validateParameters(XmlDocument xmlDocument, XmlSchema xmlSchema) { if (xmlDocument == null) { new ArgumentNullException("ValidXmlDoc() - Argument NULL: XmlDocument"); } if (xmlSchema == null) { new ArgumentNullException("ValidXmlDoc() - Argument NULL: XmlSchema"); } } private static XmlReader createXmlReader(XmlDocument xmlDocument, XmlSchema xmlSchema) { StringReader xmlStringReader = convertXmlDocumentToStringReader(xmlDocument); XmlReaderSettings xmlReaderSettings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; xmlReaderSettings.Schemas.Add(xmlSchema); return XmlReader.Create(xmlStringReader, xmlReaderSettings); } private static StringReader convertXmlDocumentToStringReader(XmlDocument xmlDocument) { StringWriter sw = new StringWriter(); xmlDocument.WriteTo(new XmlTextWriter(sw)); return new StringReader(sw.ToString()); } } }
Surfacing Validation Errors in your Test
Finding out that the XML our REST client produces matches the contract is great, however when it fails it would save a lot of time if the test just showed WHY validation failed. No problem, in our validation helper class we added a property to allow us to retrieve the validation error message in the event the test failed and output that as the failure message for the test:
XmlValidatorTestHelper xmlSchemaValidator = new XmlValidatorTestHelper(); XmlSchema myXmlSchema = XmlSchema.Read(...); XmlDocument myXmlDocument = new XmlDocument(); myXmlDocument .Load(...); xmlSchemaValidator.ValidXmlDoc(myXmlDocument, myXmlSchema); Assert.IsTrue(xmlSchemaValidator.IsValidXml, "XML does not match Schema: " + xmlSchemaValidator.ValidationError);