Saturday, 6 June 2009

Unit Testing With XLANGMessage

As a rule I generally try to pass messages from BizTalk orchestrations into .NET components using the Microsoft.XLANGs.BaseTypes.XLANGMessage object. This is an abstract base class used by the orchestration engine to represent a message and provides a performant way of marshalling message content without having to resort to using an XMLDocument. For more detail on the benefits of XLANGMessage see Jon Flanders' post on the subject.

Anyhow, whilst using XLANGMessage is a real boon for BizTalk based applications, it does raise problems when trying to write unit tests. How do I write a test for a class that uses XLANGMessage in its interface without resorting to creating an orchestration, deploying a BizTalk app, dealing with File adapters etc?

Well the solution I have adopted is to create mock XLANGMessage and XLANGPart classes that use generics to allow a specified object type to be returned when calling the RetrieveAs method. I typically use this in conjunction with a class generated from the underlying message schema using the XSD tool. I can then write simple unit test code such as:

void Test()
{
// Create and populate a new message class instance.
// Typically this would be done by deserializing an XML string.
MyMessageClass msg = new MyMessageClass();

// Create a new mock XLANGMessage to wrap the message
MockXLANGMessage<MyMessageClass> xlang
= new MockXLANGMessage<MyMessageClass>(msg);

// Call the method on the class to be tested
// passing in the mock XLANGMessage
MyClassToBeTested.DoSomething(xlang);
}


where the class to be tested looks like:



class MyClassToBeTested
{
static void DoSomething(XLANGMessage msg)
{
MyMessageClass reader =
(MyMessageClass)msg[0].RetrieveAs(typeof(MyMessageClass));
}
}


As you can see this is pretty simple code but works very effectively. But the real meat of this is the mock classes. So what do they look like? Here are simple versions which you can enhance to flesh them out if required. The key bit is the use of the generic class which provides the flexibility to wrap any class. This is utilised in the RetrieveAs implementation.



public class MockXLANGPart<T> : XLANGPart
{
T m_obj;

public MockXLANGPart(T obj)
{
m_obj = obj;
}

public override void Dispose()
{
}

public override object GetPartProperty(Type propType)
{
throw new NotImplementedException();
}

public override Type GetPartType()
{
throw new NotImplementedException();
}

public override string GetXPathValue(string xpath)
{
throw new NotImplementedException();
}

public override void LoadFrom(object source)
{
throw new NotImplementedException();
}

public override string Name
{
get { return "MockXLANGPart"; }
}

public override void PrefetchXPathValue(string xpath)
{
throw new NotImplementedException();
}

public override object RetrieveAs(Type t)
{
if (t == typeof(T))
{
return m_obj;
}

return null;
}

public override void SetPartProperty(Type propType, object value)
{
throw new NotImplementedException();
}

public override System.Xml.Schema.XmlSchema XmlSchema
{
get { throw new NotImplementedException(); }
}

public override System.Xml.Schema.XmlSchemaCollection XmlSchemaCollection
{
get { throw new NotImplementedException(); }
}
}

public class MockXLANGMessage<T> : XLANGMessage
{
List<MockXLANGPart<T>> m_parts = new List<MockXLANGPart<T>>();

public MockXLANGMessage(T obj)
{
m_parts.Add(new MockXLANGPart<T>(obj));
}

public override void AddPart(object part, string partName)
{
throw new NotImplementedException();
}

public override void AddPart(XLANGPart part, string partName)
{
throw new NotImplementedException();
}

public override void AddPart(XLANGPart part)
{
throw new NotImplementedException();
}

public override int Count
{
get { return m_parts.Count; }
}

public override void Dispose()
{
}

public override System.Collections.IEnumerator GetEnumerator()
{
return m_parts.GetEnumerator();
}

public override object GetPropertyValue(Type propType)
{
throw new NotImplementedException();
}

public override string Name
{
get { return "MockXLANGMessage"; }
}

public override void SetPropertyValue(Type propType, object value)
{
throw new NotImplementedException();
}

public override XLANGPart this[int partIndex]
{
get { return m_parts[partIndex]; }
}

public override XLANGPart this[string partName]
{
get { return m_parts[0]; }
}
}



My thanks to Anil Prasad for putting me onto this technique.

3 comments:

Mallu said...

This is beauty man....I love this xlnag unit test work around...

Scio Consulting | IntegraciĆ³n & Desarrollo said...

Thanks Man, realy usefull code!! :D

Scio Consulting | IntegraciĆ³n & Desarrollo said...

realy Thanks, very userfull piece of code, nice work around.