Testing private and internal members – add a little ‘dynamic’ sugar

Recently I was reading a blog post dealing with accessing private and internal members in tests. Visual Studio provides the PrivateObject class, that can be used to access private and internal members of a class.
Beside the fact that accessing private members in a test should generally be avoided, there are also situations where it may indeed be helpful.

Unfortunately, using PrivateObject in a test creates “noise” that makes the test harder to read. So let’s assume we want to test this class and access its _someText field:

namespace MyCupOf.Net
{
    internal class MyInternalClass
    {
        private string _someText;
    }
}

Using PrivateObject in a test method to access the private field _someText would look like this:

PrivateObject sut = new PrivateObject("MyCupOf.Net", "MyCupOf.Net.MyInternalClass");
string expected = "some text";

sut.SetField("_someText", expected);

string actual = (string)sut.GetField("_someText");
Assert.AreEqual(expected, actual);

This works as promised, but the code does not look very nice.

Fortunately, by using the C# dynamic keyword and implementing a DynamicObject we can greatly improve the readability of the test. First let’s look at the rather simple implementation of DynamicPrivateObject:

class DynamicPrivateObject : DynamicObject
{
    private readonly PrivateObject _po;

    public DynamicPrivateObject(string assemblyName, string typeName)
    {
        _po = new PrivateObject(assemblyName, typeName);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _po.SetFieldOrProperty(binder.Name, value);
        return true;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = _po.GetFieldOrProperty(binder.Name);
        return true;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, 
        object[] args, 
        out object result)
    {
        result = _po.Invoke(binder.Name, args);
        return true;
    }
}

Armed with this class, we can simplify the test method:

dynamic sut = new DynamicPrivateObject("MyCupOf.Net", "MyCupOf.Net.MyInternalClass");
string expected = "some text";

sut._someText = expected;

string actual = sut._someText;
Assert.AreEqual(expected, actual);

This looks like completely naturally assiging and reading a field value. The “noise” is under the hoods.

Hope you like it.

One thought on “Testing private and internal members – add a little ‘dynamic’ sugar

  1. Hi Florian,
    danke. Deine Version ist noch ein wenig umfangreicher, als die Variante von manicai.tumblr.com …

    => Yes, I like it. 😉

    Ciao,
    Mike

Leave a Reply

Your email address will not be published. Required fields are marked *