views:

472

answers:

3

As I develop code, I often want to unit test some of the building blocks of a class even if they are normally private. If my unit tests are inside the project, I can use "Friend" to accomplish this and still keep the functions private for normal use. But I would rather move my NUnit tests into their own separate project(s). How do I achieve the effect I'm looking for?

+6  A: 

You can't (easily) test private methods from a different project, but it's quite common to test internal methods (Friend in VB) from a test project using InternalsVisibleToAttribute. This makes Friend members accessible to another assembly.

Apparently this was new in VB 9 although it was available in C# 2... not quite sure why, but this blog post from Bart de Smet gives a quick example.

Note that if your production assembly is signed, your test assembly will need to be signed too, and you'll have to specify the public key in the InternalsVisibleToAttribute arguments.

Jon Skeet
As to why it was new in VB9, it was a cost / benefit trade off. VB has a very different way of resolving names than C# and InternalsVisibleTo very much complicates name lookup. It was too costly for VB8 and hence fell to VB9. We are actually making further changes around name resolution to (cont)
JaredPar
(cont) account for this in VB10.
JaredPar
thanks for this answer
Danny G
+1  A: 

You can use Reflection to invoke the private methods. There are plenty of samples out there to do this.

Danny G
And this is the one that helped me the most: http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
demoncodemonkey
A: 

From a quick google search: http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

The basics: (this is pasted from the code project site linked above)

        public static object RunStaticMethod(System.Type t, string strMethod,
  object []  objParams) 
    {
        BindingFlags eFlags = 
         BindingFlags.Static | BindingFlags.Public | 
         BindingFlags.NonPublic;
        return RunMethod(t, strMethod, 
         null, aobjParams, eFlags);
    } //end of method

    public static object RunInstanceMethod(System.Type t, string strMethod, 
     object objInstance, object [] aobjParams) 
    {
        BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public | 
         BindingFlags.NonPublic;
        return RunMethod(t, strMethod, 
         objInstance, aobjParams, eFlags);
    } //end of method

    private static object RunMethod(System.Type t, string 
     strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags) 
    {
        MethodInfo m;
        try 
        {
            m = t.GetMethod(strMethod, eFlags);
            if (m == null)
            {
                 throw new ArgumentException("There is no method '" + 
                  strMethod + "' for type '" + t.ToString() + "'.");
            }

            object objRet = m.Invoke(objInstance, aobjParams);
            return objRet;
        }
        catch
        {
            throw;
        }
    } //end of method
Dan Williams