The new TestFu.Gestures framework contains a set of classes to simulate user interaction, called "gestures". (Currently only the mouse is implemented)
Why gestures ?
Lately, I've tackling the Windows.Forms problem. At first, I decided to use Reflection to get the On*** methods and use them to raise the events. This method worked for simple events such as Click but was showing some serious problem when you wanted to hit events like MouseEnter and MouseLeave. Obviously the Reflection solution was not good.
On***
MouseEnter
MouseLeave
Let's think again about Form testing: we are mainly testing events that are triggered by user interaction (mouse or keyboard) so in order to test this, we should "mock" the user. The Form sees the user as a sequence of mouse or keyboard gestures, therefore, we need tools to generate artificial click, mouse moves, etc...
Gesture definition
A gesture can be any user input: mouse click, mouse move, key pressed, etc. A gesture can also be a combination of other gesture. For example, drag and drop is the sequence of mouse down, move, mouse up.
Generating mouse events
At first, I tried to simulate the mouse using the .Net class Cursor, but it was also showing limitation... so it seemed like this was a work for native methods and Interop.
Cursor
A quick googling over the subject showed that two methods from user32.dll where exactly designed for that: mouse_event and keybd_event. (I'll drop aside keybd_event for the moment). I found the correct C# signature and some example in the excellent www.pinkove.net site.
mouse_event
keybd_event
This method is harnessed in the state helper class VirtualInput which has several helper methods to simulate user interactions:
VirtualInput
// simulate a left click VirtualInput.MouseClick(); // move the mouse VirtualInput.MouseMove(10,10); // push right button down VirtualInput.MouseDown(MouseButtons.Right);
Gestures interfaces
Now, that we have a method to generate mouse events, we can start to define the TestFu.Gesture framework. A gesture is defined by a simple interface:
public interface IGesture { Form Form{get;} void Start(); }
That's pretty minimalistic. The Start method executes the gesture and the Form represents the tested System.Windows.Form instance (we need it to convert coordinates between client and screen).
It is important to note that gestures should not be executed in the main thread, otherwize you will not simulate "correctly" the user interaction. Therefore, the signature of the Start method is intended to be easily "Theard startable".
A mouse gesture is defined by the IMouseGesture that specializes IGesture:
IMouseGesture
IGesture
public interface IMouseGesture : IGesture { MouseButtons Buttons {get;} }
The Buttons property value gives the combination of mouse buttons involved in the gesture.
A simple gesture: the mouse click
To illustrate these interfaces, we show the mouse click gesture is implemented. This gesture inherits from an abstract base class MouseGestureBase, which implements IMouseGesture:
MouseGestureBase
public class ClickMouseGesture : MouseGestureBase { ... // constructors public override void Start() { VirtualInput.MouseClick(this.Buttons); } }
In fact, this example shows well that gestures implement the Metod Invocation Object pattern (if I recall well).
A gesture factory
In order to simplify things, TestFu.Gestures come with a factory for gestures object, GestureFactory. This factory contains a bunch of helper classes to save you time and keystrokes. In the following example, we use the factory to create a "click" gesture and execute it in a separate thread:
GestureFactory
Form form =...; // target form GestureFactory factory = new GestureFactory(form); IGesture clik = factory.MouseClick(); GestureFactory.Start(click);
Gesture library
This section gives the list of available gestures with example. For the example, we suppose that we have a form that contains two controls (left and right) and a factory:
Form form = ...; Control left = Form.LeftControl; Control right = Form.RightControl; GestureFactory factory = new GestureFactory(form);
// click IGesture g = factory.MouseClick(); // click control g = factory.MouseClick(left); // click location g = factory.MouseClick(new Point(10,20));
// move to location g = factory.MouseMove(new Point(...,...)); // move to the center of a control g = factory.MouseMove(left);
// drag and drop between two controls g = DragAndDrop(left,right);
// sleep 1 sec g = factory.Sleep(1000);
// click left and then right g = factory.Sequence( factory.MouseClick(left), factory.MouseClick(right) );
// click left 3 times g = factory.Repeat( factory.MouseClick(left), 3);
Page rendered at Friday, August 08, 2008 7:59:57 AM UTC
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.