Question

I am currently working on a project of mine which is a MSPaint-like WPF application. However I don't paint with pencil tools or something similar but with objects (Rectangle, Circle, Triangle etc.). I use Prism and the MVVM model to achieve testability and maintainability.

I've now run into a problem. I have a CanvasView.xaml that's (as the name suggests) the canvas I am painting on. I have implemented custom Prism CommandBehaviors (ie. MouseDownCommandBehavior) to provide a way to bind the commands of the ViewModel to the mouse actions on the canvas.

The basic setup looks like this:

public DelegateCommand<MouseEventArgs> MouseLeftButtonDownCommand { get; set; }

public CanvasViewModel(ICanvasView view, IEventAggregator eventAggregator) : base(view)
{
    m_View = view;
    m_EventAggregator = eventAggregator;
    m_EventAggregator.GetEvent<ToolboxSelectionChangedEvent>().Subscribe(OnToolboxSelectionChanged);


    MouseLeftButtonDownCommand = new DelegateCommand<MouseEventArgs>(OnMouseLeftButtonDown);
}

public void OnMouseLeftButtonDown(MouseEventArgs args)
{
    Point position = m_View.GetPosition(args);

    if(SelectedObject!=null){
        PaintObject po = SelectedObject.Clone();
        Canvas.SetLeft(po,position.X);
        Canvas.SetTop(po,position.Y);
        PaintObjects.Add(po);
    }
}

Some things not present in the code:

  • PaintObjects is a collection of PaintObject objects that a ItemsControl on the View binds to
  • PaintObject is the base class for all usable PaintObjects (Rectangle, Circle, Triangle etc.)
  • The SelectedObject (of type PaintObject) is determined by a selection process in another Prism module (Toolbox)

The question is how can I unit test the OnMouseLeftButtonDown method? The problem is that it heavily relies on MouseEventArgs and I don't really know a good way to mock/stub MouseEventArgs.

Was it helpful?

Solution

Use an additional layer to consume and emit mouse events. Then you can stub/mock out that layer for your unit tests.

OTHER TIPS

I've been able to use the WPF Event Routing system to perform this type of unit testing with an attached property, and I assume that it will work the same with any other descendants of UIElement (Windows, etc.), because the .RaiseEvent() method in this code snippet is provided by the UIElement class:

 [TestMethod]
  public void ThingsShouldHappenWhenMouseIsClicked()
  {
     // ARRANGE
     var itemsControl = new ItemsControl ();
     var myDependencyMock = new Mock<IMyDependency>();
     // provide dependency to a dependency property
     MyAttachedProperty.SetDragDropHandler(itemsControl, myDependencyMock.Object);

     var leftClickEventArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left)
     {
        RoutedEvent = UIElement.PreviewMouseLeftButtonDownEvent,
        Source = _itemsControl
     };

     // ACT
     itemsControl.RaiseEvent(leftClickEventArgs);

     // ASSERT
     myDependencyMock.Verify(x => x.TheThingHappened());
  }

I can't tell 100% for certain whether this will apply to the specific control types you've listed in your question, but hopefully this snippet will be helpful to someone.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top