Unit Testing: Exposing Private Members

Posted Thu, Oct 29 2009 16:19 by Deborah Kurata

Visual Studio 2008 (Professional Edition and above) provides a really nice set of tools for development and execution of unit tests. It is, of  course, easy for your tests to access the public properties and methods of your classes. But what about those private members?

[To begin with an overview of unit testing, start here.]

[To expose internal (C#) or friend (VB) members, see this post.]

You may have properties or methods in your class defined  to be private. This post details how to test those methods using the unit testing features in Visual Studio.

NOTE: There are some testing philosophies that recommend you never test your private members; rather you test the public/internal/friend members and assume that those will provide coverage for all of your private members as well. Regardless of your point of view on this topic, this post provides the how-to so you can decide for yourself whether you want to or not.

Let's say your Customer class has a CustomerId property that looks like this:

In C#:

private int? _CustomerId;
public int? CustomerId
{
    get { return _CustomerId; }
    private set
    {
        if (_CustomerId == null || !_CustomerId.Equals(value))
        {
            string propertyName = "CustomerId"; 
            if (!_CustomerId.Equals(value))
            {
                _CustomerId = value;
            }
        }
    }
}

In VB:

Private _CustomerId As Integer?
Public Property CustomerId() As Integer?
    Get
        Return _CustomerId
    End Get
    Private Set(ByVal value As Integer?)
        If _CustomerId Is Nothing OrElse _
                      Not _CustomerId.Equals(value) Then
            Dim propertyName As String = "CustomerId"
            If Not _CustomerId.Equals(value) Then
                _CustomerId = value
            End If
        End If
    End Set
End Property

Notice in both cases, the setter is private. The expectation is that the business object will set this value. However, you can you unit test it if you cannot set it?

The answer is PrivateObject.

PrivateObject is a class that allows test code to call class members that are not public. You PrivateObject to access private members of your class in your unit tests.

NOTE: You can also use PrivateObject for other non-public class members.

The following demonstrates how to use PrivateObject.

In C#:

/// <summary>
///A test for CustomerId
///</summary>
[TestMethod()]
public void CustomerIdTest()
{
    Customer target;
    int? expected;
    int? actual;

    // Null to Value
    target = new Customer();
    expected = 42;

    PrivateObject po = new PrivateObject(target);
    po.SetProperty("CustomerId", expected);
    actual = target.CustomerId;
    Assert.AreEqual(expected, actual, "Values are not equal");
}

In VB:

'''<summary>
'''A test for CustomerId
'''</summary>
<TestMethod()> _
Public Sub CustomerIdTest()
    Dim target As Customer
    Dim expected As Integer?
    Dim actual As Integer?

    ' Null to value
    target = New Customer
    expected = 42

    Dim po As PrivateObject = New PrivateObject(target)
    po.SetProperty("CustomerId", expected)
    actual = target.CustomerId
    Assert.AreEqual(expected, actual, "Values are not equal")
End Sub

NOTE: This is only part of the code you would need to fully test the CustomerId property.  Only one testing scenario was covered to instead focus on the PrivateObject syntax.

The code creates a new instance of PrivateObject, passing the instance of the class that has the private member you wish to access.

PrivateObject has methods such as GetProperty, SetProperty, GetField, SetField, and Invoke. These methods provide access to the private or other  non-public members of your class.

Use PrivateObject whenever you need to access a private member in your class from your unit testing code.

Enjoy!

Filed under: , , , ,

Comments

# re: Unit Testing: Exposing Private Members

Thursday, October 29, 2009 7:46 PM by CB

Is there something -- the [TestMethod()] attribute, perhaps -- that restricts PrivateObject's use?  

Or can it be used anywhere?

# re: Unit Testing: Exposing Private Members

Friday, October 30, 2009 10:09 AM by Deborah Kurata

Hi CB -

Thank you for visiting the blog.

The PrivateObject is in the following namespace:

Microsoft.VisualStudio.TestTools.UnitTesting

And the description of the class is "Allows test code to call methods and properties on the code under test that would be inaccessible because they are not public. "

I don't think it was meant to be used anywhere else.

And maybe that is a good thing? If a class has private members, it seems that they should *not* be accessed by external code? (Testing being the only exception)?

# re: Unit Testing: Exposing Private Members

Friday, October 30, 2009 2:18 PM by Urs Enzler

The only thing I miss here is a reason why I should call private members directly. If a private property or method cannot be tested by calling other public members or I have a need to test it independantly then the private member should be refactored out to a dedicated class. Otherwise, the Single Responsibility Principle is likely to be violated.

# re: Unit Testing: Exposing Private Members

Sunday, November 08, 2009 8:13 PM by Alen Siljak

Urs, the access to private methods/properties/fields is required if one does not want to change the public signature of the tested class but still wants to mock/stub the internal dependencies on other objects.

Example: you want to test SomeClass that loads some data from the database using DataClass. You don't want it to actually touch the database so you mock the DataClass to return a certain value say "3". Since SomeClass does not expose DataClass in it's public signature, the only way to cut the dependency on DataClass is to manipulate the internal variable holding the reference to DataClass and replace it with mock/stub object created outside of it.

Leave a Comment

(required) 
(required) 
(optional)
(required)