Introduction to TestApi – Part 1: Input Injection APIs
- Overview of TestApi
- Part 1: Input Injection APIs
- Part 2: Command-Line Parsing APIs
- Part 3: Visual Verification APIs
- Part 4: Combinatorial Variation Generation APIs
- Part 5: Managed Code Fault Injection APIs
- Part 6: Text String Generation APIs
- Part 7: Memory Leak Detection APIs
- Part 8: Object Comparison APIs
I am starting a series of posts introducing some of the facilities available in TestApi , a test and utility API library, which we recently released on CodePlex. Most of this content is already available in the documentation provided with the library.
The first post is on input injection – a fairly common activity in UI testing.
Input injection is the act of simulating user input. In general, there are several ways to simulate user input, in the following progressively increasing levels of realism:
- Direct method invocation: A test programmatically triggers events by directly calling methods on the target UI element. For example, a test can call the Button.IsPressed method to simulate pressing a WPF button.
- Invocation using an accessibility interface (UIA, MSAA, etc.) : A test programmatically triggers events by calling methods on an AutomationElement instance that represents the target UI element.
- Simulation using low-level input: A test simulates input by using low-level input facilities provided by the host operating system. Examples of such facilities on Windows are the SendInput Win32 API and the Raw Input Win32 API, which inject input directly into the OS input stream.
- Simulation using a device driver: A test uses a device driver to simulate input at the device-driver level.
- Simulation using a robot: A test controls a robot to simulate direct human interaction with an input device (for example, pressing keys on a keyboard).
Technique A is framework-specific; what works for WPF does not work for Windows Forms and vice versa. Technique B is less framework-specific than A, but still has limitations, because some frameworks differ in their implementations of the required accessibility interfaces. Techniques C and D are OS-specific. Technique D is significantly more difficult to implement and deploy than C, without a corresponding increase in its level of realism. Technique E is universal, albeit much slower and much more expensive than the other options.
The TestApi library provides facilities both for B (through the AutomationUtilities class) and for C (through the Mouse and Keyboard classes), which are the most generally useful techniques of input simulation.
The AutomationUtilities class provides wrappers for common UIA operations, such as discovery of UI elements. The first example below demonstrates how to discover and click a WPF Button in a WPF Window, by using the AutomationUtilities class and the Mouse class.
// // EXAMPLE #1 // This code below discovers and clicks the Close button in an About dialog box, thus // dismissing the About dialog box. // string aboutDialogName = "About"; string closeButtonName = "Close"; AutomationElementCollection aboutDialogs = AutomationUtilities.FindElementsByName( AutomationElement.RootElement, aboutDialogName); AutomationElementCollection closeButtons = AutomationUtilities.FindElementsByName( aboutDialogs, closeButtonName); // // You can either invoke the discovered control, through its invoke pattern... // InvokePattern p = closeButtons.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; p.Invoke(); // // ... or you can handle the Mouse directly and click on the control. // Mouse.MoveTo(closeButton.GetClickablePoint()); Mouse.Click(MouseButton.Left);
The second example below demonstrates how to discover a TextBox instance and type in it, using the Mouse and Keyboard classes as wrappers of common mouse and keyboard operations:
// // EXAMPLE #2 // Discover the location of a TextBox with a given name. // string textboxName = "ssnInputField"; AutomationElement textBox = AutomationUtilities.FindElementsByName( AutomationElement.RootElement, textboxName); Point textboxLocation = textbox.GetClickablePoint(); // // Move the mouse to the textbox, click, then type something // Mouse.MoveTo(textboxLocation); Mouse.Click(MouseButton.Left); Keyboard.Type("Hello world."); Keyboard.Press(Key.Shift); Keyboard.Type("hello, capitalized world."); Keyboard.Release(Key.Shift);
The Mouse and Keyboard classes in the TestApi library can be used for automating of any application, running on Windows. The classes are completely policy- and context-free – their usage is not dependent on a specific test framework or on a specific test workflow. TestApi provides full source code and XML documentation for these classes, so you can either integrate them in your own projects or reference the pre-built DLLs.
Note that, even though Mouse, Keyboard and AutomationUtilities make the life of the test automation developer quite a bit easier, UI testing is tricky and should be avoided whenever possible. It’s always preferable to design your application as a multi-tier application, with a “thin” UI layer, so that you can bypass the UI in most of your tests.