By Michael Sutton
Writing Coded UI tests is usually pretty easy: using the right tool, you can simply record some UI interactions, and the tool will generate code which will replay your actions programmatically. Well, I was trying to do that for automating OzCode’s UI tests, but it wasn't as easy as I expected. For testing OzCode’s features, we obviously need to run a Visual Studio instance with a debugged application, and play around with the different features while debugging. In our case we used an application written for demo purposes, which made it convenient for testing as well. However, performing Coded UI Tests for a Visual Studio extension is anything but trivial. Visual Studio’s UI is a complex beast, a monstrous combination of WPF and native windows, on top of which OzCode’s UI is sewn-in. Therefore, lots of code adjustments had to be made, and debugging the tests became a nightmare. This brought me to try and find a solution for easily debugging Coded UI, and it seemed only fair that I should try and harness OzCode for this debugging task. The results are here before you.
Coded UI in a nutshell
This post is about working with Microsoft's UI Testing platform: an automation platform for simulating user actions (such as hitting keyboard keys and clicking with the mouse), and verifying the expected results.
Using the Coded UI Test Builder, which is available within Visual Studio, you can record a scenario of user interactions which are then translated in to code. The generated code is grouped into UIMap classes which contain a static (i.e. hard coded through class composition) tree hierarchy of all the controls involved in the test scenario, and methods for playing back sets of actions on those controls. In practice, you usually record actions with the builder and make adjustments to the code where needed.
The core logic for finding and controlling an actual control within the tested application (which I'll refer to as the “Control Under Test” from now on), is encapsulated in the UITestControl
class. This class is the base class for a rich inheritance hierarchy of classes which support a variety of controls, such as a WpfCheckBox
, a WinButton
, etc.
A UITestControl
object is usually initialized with a parent object and some search properties that uniquely identify the control we want to reach. Then, the control under test is searched for (by calling the Find
method). Once found, the UITestControl
reaches its second phase (I'll call this the “Proxy Phase”) where it behaves as a proxy for the control under test. For instance, you can call Mouse.Click(uiTestControl)
to simulate a mouse click on the control under test.
Another way to receive actual proxies, is to simply walk through the tree by calling the GetChildren
method recursively.
The nightmare begins…
When recording user interactions, the Coded UI Test Builder tries to determine the best search properties for the control we are interacting with. Then the builder generates static C# code which eventually, at run time, creates a UITestControl
instance with the corresponding search properties, hoping for the call to Find
to actually find the control under test.
Hence, this is where things tend to get somewhat complicated; the builder may not locate enough information for actually finding the control again at run-time and interacting with it. This could be caused by a lack of search properties or by a wrong search path.
One approach may be to actually go and check the Application Under Test’s source code and try to understand its visual tree hierarchy (if the source code is available), or use tools like Snoop for exploring the hierarchy. However, both approaches tend to get tedious and are very error-prone.
Unfortunately, debugging a UITestControl
instance with Visual studio’s Debugger isn’t a practical solution either. Do to the nature of the object (i.e. a proxy which gets its data through another process), exploring its properties through the VS debugger requires all threads to run and causes timeouts to happen very often. Furthermore, the GetChildren
method is not a property and therefore does not appear when you inspect the object with the Quick-Watch window.
Wiping off the beads of cold sweat
While working on OzCode’s UI tests, I came up with a solution for relieving the pain of debugging these tests. The solution is a wrapper class for the UITestControl
class, called LoadedUITestControl
. This class relies on a proxy UITestControl
(i.e. an instance already associated to a control under test), and pre-loads information about the control and its hierarchy (up to the requested depth level), which makes it much easier to inspect under the debugger.
You can simply open the Quick-Watch window and evaluate:
LoadedUITestControl.LoadTree(uiTestControl)
If you use OzCode’s extended Quick-Watch with the great Search feature, you can quickly dig deep and find where the control you’re looking for is in the hierarchy and what properties uniquely identify it.
Implementation
The class uses Reflection and debugger display attributes to make it look just like the underlying UITestControl
in the debugger. First, the particular type of the UITestControl
is determined, and all of it’s property info is harvested through reflection,
var properties = new List<Property>(); var type = _source.GetType(); var props = from prop in type.GetProperties(Flags) where ToLoadProperty(prop) select prop; foreach (var prop in props) { ... }
Then, the properties are loaded using a smart selection (black/white list). If a property getter call takes too long, the call is aborted, and the property name is inserted into a black list. From that moment on, the black-listed property will never be called again, gaining us some nifty performance improvements. Once loaded, the properties are presented by the debugger as actual fields of the LoadedUITestControl
. This is achieved by using one of Visual Studio’s debugger best-kept secrets, the DebuggerBrowsable
attribute (and setting it to RootHidden)
. I got this idea from Jared Parson’s excellent blog-post.
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] internal Property[] Z_Properties { get { if (_properties == null) { _properties = LoadDynamicProperties(); } return _properties; } }
Usage
Different overloads of the LoadedUITestControl.LoadTree
static method can be used to configure the loading mechanism. You can use a white-list (opt-in) or black-list (opt-out) to specify what properties you want to excavate. For instance,
var loaded = LoadedUITestControl.LoadTree(root, Int32.MaxValue, LoadedUITestControl.LoadingMechanism.WhiteList, "AutomationId");
will load the tree to it’s entire depth (may take some time) retrieving only the AutomationId property where applicable (along with a few basic properties which are always loaded).
The method I described in this post made my debugging experience much smoother. I hope it will be helpful for you too. Good luck!
The source code for this article is located on Github: https://github.com/michaelsutton/coded-ui-dubugging
About the author: Michael is a software developer at CodeValue. He has an in-depth knowledge and understanding of the Microsoft .NET Framework, and is highly experienced with WPF . Michael also has a passion for native C++ development, and for low-level code in general. Michael has a B.Sc in Computer Science from JCT (Jerusalem College of Technology).
Blog: http://blogs.microsoft.co.il/michaels/
LinkedIn: http://www.linkedin.com/pub/michael-sutton/65/693/a07