Caves Travel Diving Graphics Mizar Texts Cuisine Lemkov Contact Map RSS Polski
Trybiks' Dive Texts Testing Accessing private and protected members - PrivateObject and PrivateType YAC Software
  Back

List

Charsets

Charts

DBExpress

Delphi

HTML

Intraweb

PHP

Programming

Rhino Mocks

Software

Testing

VB.NET

VCL

WPF

Accessing private and protected members - PrivateObject and PrivateType
Usually, I try to implement my unit tests by testing only publicly available members of a class. These kinds of tests are called black-box tests since they don't care what's happening inside the entity being tested, but only what outputs it generates for any given input.

I find, however, that often you'll also want to test protected and private members of a class. Some of the possible reasons for doing that:
  • a private method performs calculations that are not that easy to test via accessing public methods only (all code paths are hard to execute, the algorithm is pretty complex, the test is difficult to setup without accessing that method, etc.),
  • a private field needs to be set to a specific value for the test to run, but you don't want to make that field neither protected or public,
  • methods are hidden not because their implementation may change, but because you want to show developers how they should access an object (so, the argument of doing black-box testing because the internals may change doesn't really apply in that scenario),
  • and probably a hundred other reasons for very specific scenarios.
Though you may argue that some of the above are caused by poor design decisions, in real life it's just not that simple (for instance, you may have inherited a substantial code base and it's not feasible to restructure the code)...

Anyway, if you find that you need access to private fields and/or methods, PrivateObject comes to the rescue; let's say that we have the following class:
  Public Class Comp
  
    Private _field As Integer
  
    Private Function GetMultiple(ByVal multiplier As Integer) As Integer
      Return _field * multiplier
    End Function
  
    . . .
  
  End Class
Now, because of... whatever..., you need to access these private members in a unit test:
  <TestMethod()>
  Public Sub TestComp
    Dim comp As New Comp()
    Dim compAccessor As PrivateObject(comp)
    . . .
  End Sub
compAccessor is instantiated with the class instance under test; now, using compAccessor, you can access comp's private members:
  <TestMethod()>
  Public Sub TestGetMultiple
    Dim comp As New Comp()
    Dim compAccessor As PrivateObject(comp)
  
    compAccessor.SetField("_field", 2)
  
    Dim result As Integer = compAccessor.Invoke("GetMultiple", 5)
    Assert.AreEqual(10, result,
                    "GetMultiple shall return the product of the given value " +
                    "and the value of the internal _field variable.")
  End Sub
So, you can use SetField to set a private variable's field to a value (and GetField to retrieve that value). And than, you can use Invoke to call a sub or a function; and to retrieve the results of a function.

If you need to pass in multiple values to a method, you just pass an array of values (let's say that now GetMultiple takes two integers):
  <TestMethod()>
  Public Sub TestGetMultiple
    Dim comp As New Comp()
    Dim compAccessor As PrivateObject(comp)
  
    Dim result As Integer = compAccessor.Invoke("GetMultiple", {5, 2})
    Assert.AreEqual(10, result,
                    "GetMultiple shall return the product of the given values.")
  End Sub
If you have a private or protected property, instead of using Get/SetField, you should use Get/SetProperty. However, it's usually best to just use Get/SetFieldOrProperty that handles both versions.

Now, this gives you access to instance members; but if you want to access private shared / static members, instead of using PrivateObject, you'll need PrivateType.

Works just like private object, but instead of initializing it with an instance, you pass the class type to the constructor; and, instead of using Invoke and Get/SetX, you need to use Get/SetStaticX (e.g. GetStaticField, SetStaticProperty):
  <TestMethod()>
  Public Sub TestGetMultiple
    Dim compAccessor As PrivateType(GetType(Comp))
  
    compAccessor.SetStaticField("_field", 2)
  
    Dim result As Integer = compAccessor.InvokeStatic("GetMultiple", 5)
    Assert.AreEqual(10, result,
                    "GetMultiple shall return the product of the given value " +
                    "and the value of the internal _field variable.")
  End Sub
Happy testing!

Top

Comments
Alas!
No comments yet...

Top

Add a comment (fields with an asterisk are required)
Name / nick *
Mail (will remain hidden) *
Your website
Comment (no tags) *
Enter the text displayed below *
 

Top

Tags

Testing

VB.NET


Related pages

CA1800:DoNoCastUnnecessarily

The creator of this fault did not specify a Reason.

Saving / restoring window placements in .NET

Get the TreeViewItem for an Item in a WPF TreeView

Double Clicks in WPF TreeView Controls

Output in MSTest Tests (VS 2010)

Checking Property Change Notifications

Checking "Dangling" Event Handlers in Delphi Forms

Rhino Mocks's AssertWasCalled in VB.NET

First steps with Rhino Mocks (in VB.NET)

Meaningful identifiers

Public fields vs. properties

VS Pending Tests

Automated GUI Testing

Automated GUI Testing in VMs

Automated Testing of Window Forms

Detecting Memory Leaks with DUnit