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.