chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes

I'm trying to write a test case where I need to mock XmlTextReader, XmlDocument and XmlNode (well, at least I think I need to mock these things)

We've a class called ShiftInfo whose constructor loads global configuration file (which is actually a plain XML document) and reads a connection string (and of course some other information) and initializes the instance.

// constructor's sample code
public ShiftInfo()
  XmlTextReader reader = new XmlTextReader("http://server/config.xml");
  XmlDocument doc = new XmlDocument();
  _someConnString = doc.SelectSingleNode("/ConnectionStringToDB").InnerXml;

We are using NUnit to do the unit testing and evaluating TypeMock.
The very first test case we have is supposed to mock that file exists on the server. It also tries to mock that file has expected node.

// First test case to mock file exists and file has expected node
public ConstructorTest()
  string expectedConnectionString = "Data Source=;Database;User Id=;Password=";
  MockObject mockedNode = MockManager.MockObject(typeof(XmlNode), Constructor.NotMocked);
  mockedNode.ExpectGet("InnerXml", expectedConnectionString);
  XmlNode xmlNode = (XmlNode)mockedNode.Object;
  MockObject mockedDoc = MockManager.MockObject(typeof(XmlDocument));
  mockedDoc.ExpectCall("Load", typeof(XmlReader));
  mockedDoc.ExpectAndReturn("SelectSingleNode", xmlNode).Args("/ConnectionStringToDB");
  ShiftInfo si = new ShiftInfo();

  Assert.AreEqual(expectedConnectionString, si.ConnectionString);

Now, I must agree as a test this code does not make any sense at all. But, when I try to run, I get the following exception

Nucor.Hickman.Web.NHSystem.HeaderShiftInfo.Tests.ShiftInfoTests.Constructor : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.MethodAccessException : System.Xml.XmlNode..ctor()


at System.RuntimeMethodHandle._InvokeConstructor(Object[] args, SignatureStruct& signature, IntPtr declaringType)
at System.RuntimeMethodHandle.InvokeConstructor(Object[] args, SignatureStruct signature, RuntimeTypeHandle declaringType)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at TypeMock.MockManager.MockObject(Type type, Constructor mockConstructors, Object[] args)
at Nucor.Hickman.Web.NHSystem.HeaderShiftInfo.Tests.ShiftInfoTests.Constructor() in C:dotNetNucorHickmanWebNHSystemHeaderShiftInfoNucor.Hickman.Web.NHSystem.HeaderShiftInfoTestsShiftInfoTests.cs:line 69
at MockXmlNode..ctor()

I searched for this error and I found couple of posts from 2005 that suggested that the support has been added to precompiled libraries in the newer versions. So, I'm guessing there is something that I'm doing and I'm doing it terribly wrong.

In my deference, this is my first time in using mock objects and whole mocking thing :wink:

If you could just point me in the right direction that would suffice too... But, of course more detailed explanation or examples would be great

asked by shatru2k (600 points)

1 Answer

0 votes
You are doing really well for a first timer.
You are right, the CLR doesn't allow you to mock XmlNode.
I have added a feature request to try and bypass this issue but in the mean-time here is a workaround, which allows you to load a test xml.
I personally think that this is a better way.

Note: You will need a License to do this
Swap the XmlTextReader to point to a test xml
public void ConstructorTestTopic_4802()
    string expectedConnectionString = "Data Source=;Database;User Id=;Password=";

    // change url to point to test xml
    Mock m = MockManager.Mock(typeof(XmlTextReader));
    m.ExpectUnmockedConstructor().Args(new Assign("test.xml"));

    ShiftInfo si = new ShiftInfo();

    Assert.AreEqual(expectedConnectionString, si.ConnectionString);

(If instead of hardcoding the url, you use a Property, you will be able to mock that property.)
answered by scott (32k points)