A A
RSS

Unit Test Private Methods in Visual Studio

Wed, Jul 9, 2008

ASP.NET MVC, Programming, Testing

I am working on a feature that will let me import twitter messages to yonkly and wanted to write a test for it.  The method is private and I couldn’t get the unit test to see it.  I also didn’t want to use the private accessor class generate by Visual Studio because I was mocking some functionality in the actual class and didn’t really fell like re-mocking it on the private accessor.

So, after several minutes of googling, I found several solutions that I didn’t like.  John Hann uses reflection to test private methods.  Tim Stall has a similar solution at the code project.  Andrew Stopford suggested that I don’t test private methods and use code coverage to make sure that they are being exercised.  I was about to use the methods suggested by John Hann and Tim Stall to test my private methods, but then I accidentally (thanks to IntelliSense) discovered PrivateObject.

The PrivateObject class is part of the Team Test API.

Allows test code to call methods and properties on the code under test that would be inaccessible because they are not public.
from msdn

It turned out to be pretty easy to test private methods and the code looked like this:

var myController = new TwitterController();
var po = new PrivateObject(myController);
var page = 1;
var count = 25;
po.Invoke("ImportTweets", new object[] { page, count });

 

The code above will call the private method ImportTweets and pass it two integer parameters.  This is the equivalent of calling

myController.ImportTweets( page, count);

 

Note that this is essentially what John Hann and Tim Stall suggested but why use extra code when PrivateObject is already available for you.

Tags: , , , , , , , ,

  • Doug de la Torre
    The downside to using PrivateObject is that it is a bit painful to maintain, since signature changes are not caught at compile-time, but instead caught at test-time. Refactorings that change method signatures tend to catch all the compile-time stuff, but then leave test code broken, and it is tougher to fix.

    An alternative that I've always liked is to use inner-classes to test your code, like this:

    public class Foo
    {
    private void Bar()
    {
    // Do so work here in a private method
    }

    #region Unit Tests
    #if UNIT_TESTS
    [TestFixture] public class TestFoo
    {
    [Test] public void TestBar()
    {
    Foo foo = new Foo()
    foo.Bar(); // inner class can call this method
    }
    }
    #endif
    #end region
    }

    You simply define UNIT_TESTS in Debug/Release builds if you want test code enabled, and leave it out from your Ship builds.

    Also, you'll probably have a using statement wrapper,

    #if UNIT_TESTS
    using MbUnit.Framework;
    #endif

    As an added check, you can write a simple app that does reflection on all the types in the DLL to verify your ship build doesn't have any classes with test attributes. If no code references the test framework, your ship builds will automatically not load the referenced test framework DLLs, thus allowing you to ship your product like usual without pulling in test DLL dependencies (and associated bloat and licensing issues).
  • That's a pretty good idea except for the fact that it "pollutes" the
    code.
  • Do you know of a way that you can do this with managed C++ that references unmanaged C++ types? Please see this question: http://stackoverflow.com/questions/916507/how-t...
  • Sorry, but the last time I used c++ was in college :)
  • stephen
    Brilliant Idea, been looking for a straight forward solution to this scenerio that did not invlove using heavyweight reflection.
blog comments powered by Disqus
Advertise Here

What I'm Doing...

Yonkly Open Source

Sign up for my newsletter

powered by MailChimp!

Cyber Identity