Freigeben über


Testing Private Methods/Member Variables - Should you or shouldn't you

One of the often requested features of NUnit was the ability to test private member variables and private methods. I resisted because I always felt that if you limited yourself to the public interface that enabled you to freely change the implementation without having to change the tests. This I believe is a good thing because if the tests require a lot of maintenance you might be tempted to not do it.  However, the flip side of the equation is you may end up exposing a method or worse yet a member variable only for testability. The downside of this is that once it is present in the interface it could be used for something else. So, as usual there are arguments on either side.

.NET, through reflection, provides the ability to invoke private methods and see the values of private member variables so it is not impossible to do this even today. However, the unit testing tool in VS Team System has a built-in wrapper, called PrivateObject, to make the syntax a bit easier to digest.

Here is an example:

using

Microsoft.VisualStudio.QualityTools.UnitTesting.Framework;

public

class TestedClass
{
    private bool privateField = true;

    private bool PrivateMethod()
{
return privateField;
    }
}

[TestClass]
public class PrivateTest
{
    private PrivateObject privateObject;

    [TestInitialize]
    public void Initialize()
    {
        TestedClass testedClass = new TestedClass();
        privateObject = new PrivateObject(testedClass);
    }

[TestMethod]
    public void PrivateField()
    {
        bool field = (bool)privateObject.GetField("privateField");
        Assert.IsTrue(field);
    }

    [TestMethod]
    public void PrivateMethod()
    {
        bool result = (bool)privateObject.Invoke("PrivateMethod");
        Assert.IsTrue(result);
    }
}

As with all capabilities there is a right time and a wrong time to use them. I will be spending more time on this over the next few weeks but I would really like to get your feedback about this and recommendations on practice.

This posting is provided "AS IS" with no warranties, and confers no rights.

Comments

  • Anonymous
    June 07, 2004
    I am split on whether or not we should be performing tests on private members. When I was first introduced to TDD by a former coworker, his philosophy was "develop for testability". And this would involve exposing members just for the purpose of developing tests against them. Of course, I have come to realize this is a horrible idea. If I were to lean one way, I would say testing only the public interfaces is the way to go. When someone consumes your object, they are only using the public interfaces so writing tests against these members makes sense. However, I can also understand the argument to hit against the private members.
  • Anonymous
    June 07, 2004
    That's pretty nice. In 99 out of 100 cases, I'd agree that your setting yourself up for a world of hurt if you test this way. It would be better to refactor your code so that the private code gets tested via the appropriate usage of the public interface.

    However, this is nice for that 1 case in 100 when you really need to get at the private members to save time in writing tests.
  • Anonymous
    June 07, 2004
    When all you have is a hammer....

    The internals of an object certainly should be tested in some way. But unit tested? I don't think so.
  • Anonymous
    June 07, 2004
    I like to write all my tests as a part of my class that I am working on. This requires me to have #ifdef all over the place, but I don't mind too much.

    That said, I do not test member variables. I only test functions/properties.

    I don't like having to make things marked as internal, public just so that I can test it. But I also do test things marked as protected and private. If I have my tests at a granular level, I may have to change my tests more often, but they are more akin to what I would do debugging.

    I will experiment with the idea of only testing public interfaces.
  • Anonymous
    June 08, 2004
    The comment has been removed
  • Anonymous
    June 16, 2004
    Jay Bazuzi adds some additional information on his blog, check it out.

    http://weblogs.asp.net/jaybaz_ms/archive/2004/06/11/153978.aspx
  • Anonymous
    July 29, 2004
    While I think this should be rarely used, I think that its important to have the ability to test private methods in certain cases.

    Where can I find PrivateObject? Team System is not available yet to the public, right? The best I could find was: http://weblogs.asp.net/stevencohn/archive/2004/06/08/151235.aspx and that isn't quite the same as the above.

    Thanks.
  • Anonymous
    December 09, 2007
    PingBack from http://www.woloszyn.org/2007/12/09/to-test-or-not-to-test/