Функции модульного тестирования, основанные на MouseEventArgs?
-
13-09-2019 - |
Вопрос
В настоящее время я работаю над своим проектом, который представляет собой приложение WPF, подобное MSPaint.Однако я рисую не карандашами или чем-то подобным, а объектами (прямоугольник, круг, треугольник и т. д.).Я использую Prism и модель MVVM для обеспечения тестируемости и удобства обслуживания.
Теперь я столкнулся с проблемой.У меня есть CanvasView.xaml, который (как следует из названия) представляет собой холст, на котором я рисую.Я реализовал собственные свойства Prism CommandBehaviors (т.MouseDownCommandBehavior), чтобы обеспечить способ привязки команд ViewModel к действиям мыши на холсте.
Базовая настройка выглядит так:
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);
}
}
Некоторые вещи отсутствуют в коде:
- PaintObjects — это коллекция объектов PaintObject, к которым привязывается ItemsControl в представлении.
- PaintObject — это базовый класс для всех используемых объектов PaintObject (прямоугольник, круг, треугольник и т. д.).
- SelectedObject (типа PaintObject) определяется процессом выбора в другом модуле Prism (Toolbox).
Вопрос в том, как я могу протестировать метод OnMouseLeftButtonDown?Проблема в том, что он сильно зависит от MouseEventArgs, и я не знаю хорошего способа имитировать/заглушить MouseEventArgs.
Решение
Используйте дополнительный слой для потребления и генерации событий мыши.Затем вы можете заглушить/макетировать этот слой для своих модульных тестов.
Другие советы
Мне удалось использовать систему маршрутизации событий WPF для выполнения этого типа модульного тестирования с прикрепленным свойством, и я предполагаю, что она будет работать так же с любыми другими потомками UIElement (Windows и т. д.), потому что .RaiseEvent () в этом фрагменте кода предоставляется классом UIElement:
[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());
}
Я не могу со 100% уверенностью сказать, применимо ли это к конкретным типам элементов управления, которые вы указали в своем вопросе, но, надеюсь, этот фрагмент будет кому-то полезен.