After my blog on MbUnit’s RowTest feature, a commenter mentioned:
“Wouldn’t you think it is better to move such data into an XML file. Keeping test data separated from test logic? You can also enable sharing of data across tests”
Well, yes that would be ideal and MbUnit already has the support for this feature via the DataFixture attribute.
The DataFixtureAttribute together with XmlDataProvider and ForEachTest allows you to store your test data in a external XML file and for each XML Node, execute a test with access to the data.
Again, I am testing my simple Add method. However, instead of using RowTest to store the data for each test, I have moved the tests into their own XML file, called DataFixtureSample.xml which contains:
These are my three tests, I could include additional data in the XML Node however I have left it as just the test data. The element names can be anything and are set out within your own test code.
The code for my test fixture is below.
[MbUnit.Framework.DataFixture]
[XmlDataProvider(@”E:My DocumentsVisual Studio 2005ProjectsMbUnitSamplesMbUnitRowTestDataFixtureSample.xml”,
“DataFixture/Test”)]
public class DataFixtureSample
{
[ForEachTest(“Data”)] //Gotcha – Don’t include a slash!! “/Data” causes it not to display in UI
public void TestAddMethodUsingXML(XmlNode node)
{
int test = MyMethods.Add(Convert.ToInt32(node.Attributes[“a”].InnerText), Convert.ToInt32(node.Attributes[“b”].InnerText));
Assert.AreEqual(test, Convert.ToInt32(node.Attributes[“expected”].InnerText));
}
}
The class needs to be decorated with the DataFixture attribute. XmlDataProvider then takes in the full path to the xml test data, and the XPath for how the framework can find each test data node.
My tests are then decorated with the ForEachTest attribute with a parameter of the XML Node name. A small gotcha here – Don’t include a slash “/Data” causes it not to display in UI.
My test accepts a standard XmlNode which will refer to the XmlNode within the test data. Each node in the xml file is tested separately in their own test.
From within my test, I can access the XmlNode normally. In this case, I am getting the InnerText and casting it to a Int32 so it can be used in my add method.
However, MbUnit allows us to tidy this code up for us by allowing each XmlNode to be strongly typed to an object. In the code I have created a class for the Data node which relates to the Xml.
[XmlRoot(“Data”)]
public class Data
{
public Data()
{ }
[XmlAttribute(“a”)]
public int a;
[XmlAttribute(“b”)]
public int b;
[XmlAttribute(“expected”)]
public int expected;
public override string ToString()
{
return String.Format(“{0} + {1} = {2}”, a, b, expected);
}
}
I then change the attribute and parameter on the test method to be:
[ForEachTest(“Data”, DataType = typeof(Data))]
public void ForEachTestWithSerialization(Data data)
Now, each XmlNode is just an object in my test so I can simple write data.expected to get the Int32 value from the Xml Node using serialisation. Great feature!!!!
We can then take the code to the next level by removing the need to hardcore the path to the Xml test file.
By changing XmlDataProvider for ResourceXmlDataProvider and setting the Xml Test File as a Embedded Resource in our build we can have the code like below:
//Make sure you set the xml file as Build Action : Embedded Resource
[ResourceXmlDataProvider(typeof(DataFixtureSampleResource), “MbUnitSamples.DataFixtureSample.xml”, //’MbUnitSamples.’ is my project name.
“DataFixture/Test”)]
This makes the code a lot more flexible when accessing it from different machines, such as developers and build, as the file doesn’t always have to be in the same place.
This is a set of great features and allows you to separate your test data from your test code, together with the serialisation it allows us to maintain readable tests.
If you interested in any other feature, or want to know more then please get in touch.
Code/Sources/More Information:
http://blog.benhall.me.uk/code/mbunit/DataFixtureSample.xml
http://blog.benhall.me.uk/code/mbunit/DataFixture.cs.txt
http://weblogs.asp.net/astopford/articles/257001.aspx
http://www.mertner.com/confluence/display/MbUnit/DataFixture