65.9K
CodeProject is changing. Read more.
Home

Testing Private Members in Visual Studio

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1 vote)

Jun 12, 2009

CC (Attr 3U)

2 min read

viewsIcon

18525

How to test private members in Visual Studio

I’m currently working on a CommandBehaviour class to enable me to fire commands in response to arbitrary routed events on elements that don’t natively support commands, inspired by Sacha Barber’s post: WPF: Attached Commands.

Whilst trying to apply some unit tests to what I’m writing, I came across the age old problem of how to test things which are private by design. Under normal circumstances, I would probably have made them protected and written a TestableCommandBehaviour class in the test project that inherits from CommandBehaviour and exposes the protected members that I wanted to test.

However, in this particular instance, I’d already written the code, so I used the Create Unit Tests feature in Visual Studio to generate some unit tests for me to get me started. What I didn’t realise before was that when you do this, it creates a “Test Reference”, which provides you with a private accessor that you use to access the private code*.

Here’s a cut down version of the CommandBehaviour class:

   1:  namespace DerekLakin.Libraries.Presentation
   2:  {
   3:      public class CommandBehaviour
   4:      {
   5:          public static readonly DependencyProperty CommandProperty =
   6:            DependencyProperty.RegisterAttached(
   7:              "Command",
   8:              typeof(ICommand),
   9:              typeof(CommandBehaviour),
  10:              new UIPropertyMetadata(null));
  11:   
  12:          public static readonly DependencyProperty CommandParameterProperty =
  13:            DependencyProperty.RegisterAttached(
  14:              "CommandParameter",
  15:              typeof(object),
  16:              typeof(CommandBehaviour),
  17:              new UIPropertyMetadata(null));
  18:   
  19:          public static readonly DependencyProperty EventNameProperty =
  20:            DependencyProperty.RegisterAttached(
  21:              "EventName",
  22:              typeof(string),
  23:              typeof(CommandBehaviour),
  24:              new UIPropertyMetadata(string.Empty, 
			new PropertyChangedCallback(EventNameChanged)));
  25:   
  26:          private static readonly DependencyProperty CommandBehaviourProperty =
  27:            DependencyProperty.RegisterAttached(
  28:              "CommandBehaviour",
  29:              typeof(CommandBehaviour),
  30:              typeof(CommandBehaviour),
  31:              new UIPropertyMetadata(null));
  32:   
  33:          private readonly WeakReference sourceElement;
  34:          private EventInfo eventInformation;
  35:          private Delegate targetDelegate;
  36:   
  37:          private CommandBehaviour()
  38:          {
  39:          }
  40:   
  41:          private CommandBehaviour(DependencyObject source)
  42:          {
  43:              this.sourceElement = new WeakReference(source);
  44:          }
  45:          ...
  46:      }
  47:  }

A CommandBehaviour instance is created when the EventName attached property is set and the targetDelegate member is set when the relevant event has been hooked. In my unit test, I wanted to check that this member was actually being set and here’s how I did it using the accessor:

   1:  [TestMethod]
   2:  [DeploymentItem("DerekLakin.Libraries.Presentation.dll")]
   3:  public void RemoveEventHandlerTest()
   4:  {
   5:      Grid source = new Grid();
   6:      source.SetValue(
   7:          CommandBehaviour.CommandProperty,
   8:          ApplicationCommands.Open);
   9:      source.SetValue(
  10:          CommandBehaviour.EventNameProperty,
  11:          "MouseLeftButtonUp");
  12:      CommandBehaviour real = (CommandBehaviour)
  13:          source.GetValue(
  14:              CommandBehaviour_Accessor.CommandBehaviourProperty);
  15:      CommandBehaviour_Accessor target = 
  16:          new CommandBehaviour_Accessor(
  17:              new PrivateObject(real));
  18:      Assert.IsNotNull(target.targetDelegate);
  19:      target.RemoveEventHandler();
  20:      Assert.IsNull(target.targetDelegate);
  21:  }

First, I create a Grid instance and set the Command and EventName attached properties on it. Next, I get the CommandBehaviour instance from the Grid instance by using the accessor’s CommandBehaviourProperty (which is normally private). Then, I create a CommandBehaviour_Accessor instance that wraps the CommandBehaviour instance by using the PrivateObject class. Finally, I use regular Assert statements against the accessor to check the private members. Job done!

* For more information about testing private methods, see How to: Test a Private Method on the MSDN web site.

This work is licensed under a Creative Commons Attribution By license.