Saturday, November 23

Testing private methods via reflection


You are not supposed to test the private methods of a class, but it is occasionally useful. Microsoft used to have a private accessor type but has since deprecated it. This is the way I came up with: Put a pulic wrapper around the methods, and use reflection to call them. Not original, but it works ok.

The reflection class has one main method: RunMethod. I added (ok, started with) a ListMethod as a helper.


namespace UnitTests.Accessors
{
    using System;
    using System.Reflection;

    /// <summary>
    /// Accessor helper, uses reflection to call private methods of a class
    /// </summary>
    class AccessorReflection
    {
        /// <summary>
        /// The BindingFlags flags used to access the class methods
        /// BindingFlags.NonPublic will not return any results by itself. 
        /// As it turns out, combining it with BindingFlags.Instance does the trick.
        /// </summary>
        private const BindingFlags accessFlags =
            BindingFlags.Instance | BindingFlags.Public |
            BindingFlags.NonPublic | BindingFlags.Static;

        /// <summary>
        /// Runs the method of the class type.
        /// </summary>
        /// <param name="objectType">The class type.</param>
        /// <param name="methodName">The method to run as a string.</param>
        /// <param name="objectInstance">The object instance.</param>
        /// <param name="objectParameters">The object method parameters.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentException">There is no method ' +
        ///                      strMethod + ' for type ' + t.ToString() + '.</exception>
        public static object RunMethod(Type objectType, string methodName,
            object objectInstance, object[] objectParameters)
        {
            if (String.IsNullOrEmpty(methodName))
            {
                throw new
                    ArgumentException("Cannot invoke null or empty method for type " + objectType.ToString() + "'.");
            }
            MethodInfo m = objectType.GetMethod(methodName, AccessorReflection.accessFlags);
            if (m == null)
            {
                // Method does not exist
                throw new ArgumentException("There is no method '" +
                    methodName + "' for type '" + objectType.ToString() + "'.");
            }

            return m.Invoke(objectInstance, objectParameters);
        }

        /// <summary>
        /// Lists the methods of the type. Pretty much for debugging
        /// </summary>
        /// <param name="t">The class type.</param>
        public void ListMethods(Type t)
        {
            Console.WriteLine("***** Methods *****");
            MethodInfo[] methodInfo = t.GetMethods(AccessorReflection.accessFlags);
            // sort methods by name
            Array.Sort(methodInfo,
                    delegate(MethodInfo methodInfo1, MethodInfo methodInfo2)
                    { return methodInfo1.Name.CompareTo(methodInfo2.Name); });
            foreach (MethodInfo methodEntry in methodInfo)
            {
                // Get return type.
                string retVal = methodEntry.ReturnType.FullName;
                string paramInfo = "( ";

                // Get params.
                foreach (ParameterInfo parameterInfo in methodEntry.GetParameters())
                {
                    paramInfo += string.Format("{0} {1} ", parameterInfo.ParameterType, parameterInfo.Name);
                }
                paramInfo += " )";

                // Now display the basic method sig.
                Console.WriteLine("->{0} {1} {2}", retVal, methodEntry.Name, paramInfo);
            }
            Console.WriteLine();
        }

    }
}


I also added a base abstract class to call it:

namespace UnitTests.Accessors
{
    using System;

    ///
    /// Base class to access private methods for testing.
    ///
    /// Object under test
    class AccessorBase
    {
        ///
        /// Holds the reference to the object under test
        ///
        private T objectInstance;
       
        public AccessorBase(T objectInstance)
        {
            this.objectInstance = objectInstance;
        }

        ///
        /// Executes the private method of the instance
        ///
        /// Method to execute as a string
        /// Parameters for the method
        /// The result of the method execution
        public object RunMethod(string methodName, Object[] parameters)
        {
            return AccessorReflection.RunMethod(objectInstance.GetType(), methodName, this.objectInstance, parameters);
        }
    }
}

So now write an accessor class with the public wrappers. My example is dumb but it gets the point across.

class Mine
{
    private int count;

    public Mine(int count)
    {
        this.count = count;
    }

    public void publicMethodNoArgs()
    {
        this.privateMethodNoArgs();
    }

    private void privateMethodNoArgs()
    {
        int joy = 1;
        for (int x = 1; x < 5; x++)
        {
            joy += x;
        }
    }

    private void privateMethodIntArg(int joy)
    {
        Console.WriteLine("Joy before is {0}", joy);
        for (int x = 1; x < 5; x++)
        {
            joy += x;
        }

        Console.WriteLine("Joy is now {0}", joy);
    }

    private int privateMethodStringArg(string name)
    {
        int result = 1;
        return result;
    }
}


The accessor class looks like:

class Mine_Accessor : AccessorBase<Mine_Accessor>
{
    public Mine_Accessor(Mine mineInstance): base(mineInstance)
    {
    }

    public void privateMethodIntArg(int joy)
    {
        Object[] parms = {joy};

        base.RunMethod("privateMethodIntArg", parameters);
    }
}
I like to make the public wrapper look like the private method in names and parameters. If there is a return type other than void, add a return and cast the result.

No comments: