Click here to Skip to main content
15,867,330 members
Articles / Programming Languages / C#

Testing Private Members in Visual Studio

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
14 Apr 2010CC (Attr 3U)2 min read 18.2K   11   1
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:

C#
 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:

C#
 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.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution 3.0 Unported License


Written By
Software Developer (Senior)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGood point, interesting Pin
Emile van Gerwen15-Jun-09 21:51
Emile van Gerwen15-Jun-09 21:51 
Thanks for pointing out the private accessor feature. I didn't know that.

Your example is very complicated to wade through. I think your article would improve if your example is straight forward and focusses on the private accessor. In addition you could tell a little bit more about the PrivateObject you use.

Thanks again!

Emile.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.