dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.09k stars 1.17k forks source link

make MouseDevice mockable #5743

Open trivalik opened 2 years ago

trivalik commented 2 years ago

The class https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/MouseDevice.cs does not allow right now to derive from it. This prevent any Mocking library to work.

As far as I can see is it enough to change the access modifier from internal abstract MouseButtonState GetButtonStateFromSystem(MouseButton mouseButton);

Code to test with Moq:

var t = typeof(InputManager).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], null);
var mouseDevice = new Moq.Mock<MouseDevice>((InputManager)t.Invoke(null)).Object;
miloush commented 2 years ago

While I don't think 'mockability' was at any point part of the design and if desired, it should be probably addressed more broadly than picking on a random class, but I do think there is a merit in the claim since the KeyboardDevice does not have the same problem:

  protected abstract KeyStates GetKeyStatesFromSystem( Key key );

If a direct access is required for other classes (i.e. stylus), perhaps protected internal would be a more appropriate choice.

ghost commented 1 year ago

This submission has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 14 days.

It will be closed if no further activity occurs within 7 days of this comment.

trivalik commented 1 year ago

It is not just picking a random class, it is required to fake mouse clicks in unit test. This would lead into a small footprint on run unit test, instead of making a test which execute the whole program and use i.e. FlaUi to do the mouse action. But if this is the way to go, then close the issue.

trebahl commented 1 month ago

@trivalik I had a similar request and after some help by miloush I was able to devise a workaround using reflection: https://github.com/dotnet/wpf/discussions/9880#discussioncomment-10870177

This function sets the pointer location in Mouse.PrimaryDevice so that GetLocation for the specified control will return the specified coordinates (or close).

So you just need to call this function before sending a mouse event to a control.

PS: the control needs to be inside a Window (probably shown) for it to work.