Sunday, April 29, 2007

Testing Non-Public members with MbUnit (Part II).

Earlier this month I talked about how to test non-public members with MbUnit. Well there’s an interesting discussion on MbUnit group. As a result a new code was written.

Following methods are marked as obsolete. My guess is that these methods are going to be gone completely in version 3.

Old MethodNew Method
 GetNonPublicField  GetField 
 GetNonPublicVariable  GetField 
 GetNonPublicProperty  GetProperty 
 RunPrivateMethod  InvokeMethod 
 RunNonPublicMethod  InvokeMethod 


There're also new methods:
SetField - Sets field value.
SetProperty - Sets property value.

Thanks to Jeff who pointed out that Reflector didn’t have these methods. He also mentioned that method names between static and instance implementation are inconsistent. This also was corrected.

Let's create SampleClass:


public class SampleClass
{
  public string publicString = "MbUnit Rocks!!!";
  private DateTime privateDateTime = DateTime.Today;

  internal DateTime InternalProperty
  {
    get { return privateDateTime; }
    set { privateDateTime = value; }
  }

  private static int Add(int x, int y)
  {
    return x + y;
  }
}



Here an example how we can create tests for SampleClass:



TestSample _sampleObject;
Reflector _reflect;

[TestFixtureSetUp]
public void Init()
{
  _sampleObject = new SampleClass();
  _reflect = new Reflector(_sampleObject);
}

[Test]
public void GetPublicField()
{
  Assert.AreEqual("MbUnit Rocks!!!", _reflect.GetField("publicString"));
}

[Test]
public void SetNonPublicProperty()
{
  string propertyName = "InternalProperty";
  DateTime dt = new DateTime(2008, 1, 1);
  _reflect.SetProperty(propertyName, dt);
  Assert.AreEqual(dt, _reflect.GetProperty(propertyName));
}

[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, _reflect.InvokeMethod("Add", 1, 6));
}



I mentioned before that static and instance methods now have consistent names.
You can implement StaticPrivateMethod test like this using static implementation of InvokeMethod(..).


[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, Reflector.InvokeMethod(new SampleClass(), "Add", 1, 6));
}



Here's another of Jeff's suggestions:
Indicating public vs. non-public is useful for documentation purposes.


Once again, because of Jeff's suggestion we have AccessModifier enum type and using it we can specify if we want to access public, static, or non-public member. In examples above we didn't use AccessModifier. It means that Reflector will invoke method or access field or property as long as an object has implementation for it.

In the example below we are trying to test Add method that has private static modifier. However, if Add method wasn't static or was public, an assirtion would happen in our test.



[Test]
public void StaticPrivateMethod()
{
  Assert.AreEqual(7, _reflect.InvokeMethod(AccessModifier.Static | AccessModifier.NonPublic, , "Add", 1, 6));
}



It's a new code that was checked in; however, it has not been built yet. These and some other new features should be available in a next MbUnit build.