We have been receiving numerous queries related to record and playback in Coded UI Test. In most of the scenarios, some additional information is sought after to debug and nail the issue. In this post, I will enumerate some basic validations that you (as a Coded UI Test user) can attempt to troubleshoot the problem. I’ll also mention a few workarounds that you can try out for some common failure scenarios. If all of these approaches do not solve the issue, you can very well post your query with a minimal repro step and associated data to the Coded UI Test forum and we’ll respond to it.

In an ideal world, you would be able to playback whatever script was generated out of your recorded scenario. The recorder though has some of its limitations; it could be some optimizations brought into the recorder to keep a balance between performance and resilience, or it could be some accessibility issues with the application under test itself. I will start to explain the various playback failures you might encounter and then relate it back to what might have gone wrong with the recording.

First of all, do go through the post here to understand how the Coded UI Test playback search works. There is one more aspect of the search i.e. Window search which is well explained over here. From performance perspective, there are a huge number of MSDN forum threads existing that you can refer to by doing a quick search.

 

Troubleshooting playback search failures

1. Validate the control’s existence

Double check (visually) that the control indeed exists in the application when the search failed. The application may be having certain behavior such that the control does not consistently appear. An example would be a troubleshooting page in MSDN where you may or may not see an optional feedback section at the bottom of the page. If this is indeed the case, you would need to tweak your test automation code to make this action optional by enabling ‘ContinueOnError’.

Playback.PlaybackSettings.ContinueOnError = true;

// Action on the control that occurs inconsistently in the test flow.

Playback.PlaybackSettings.ContinueOnError = false;

2. WaitForReady Issues

In continuation with [1], if the control comes into existence albeit after some delay, you might need to apply some wait features provided in the playback. Check the related blog here.

3. Examining and fixing the “bad” ancestor in search hierarchy

Locate the UI control (for which search failed) using Coded UI Test builder’s control locator. You’ll come up with something like the following snapshot:

 


 
Assume the search failed for UIDCheckBox control. Starting from UIDCheckBox till UIBasicFormWindow, select the UI object up at each level and click on the Refresh properties button to validate if the search is successful for that control. Say, the refresh is not successful till UIDTreeItem, but is successful for UINotMyComputerTreeItem.  It implies, the search is broken in between these 2 objects. Check if the refresh of UINotMyComputerTreeItem actually locates (blue rectangle highlighter) the “Not My Computer” or some other control, say the “My Computer” Tree Item.  If this is the case, then both these items would be having the same identification properties and the
search hits the “My Computer” control and tries to search for the “D:” tree item within it (and hence fails; assuming there is no other ‘D:’ item under “MyComputer”).

Another way of validating this is (which is essentially a similar approach, but top-down) to highlight the controls along the hierarchy top-down in your test code and see where it goes off-track.

            WpfCheckBox uIDCheckBox = this.UIBasicFormWindow.UITreeView2Tree.UINotMyComputerTreeItem.UIDTreeItem.UIDCheckBox;

            // Highlight to visually verify the search path

            this.UIBasicFormWindow.DrawHighlight();

            this.UIBasicFormWindow.UITreeView2Tree.DrawHighlight();

            this.UIBasicFormWindow.UITreeView2Tree.UINotMyComputerTreeItem.DrawHighlight();

            this.UIBasicFormWindow.UITreeView2Tree.UINotMyComputerTreeItem.UIDTreeItem.DrawHighlight();

            this.UIBasicFormWindow.UITreeView2Tree.UINotMyComputerTreeItem.UIDTreeItem.UIDCheckBox.DrawHighlight();

            // Right-Click 'D:' check box

            Mouse.Click(uIDCheckBox, MouseButtons.Right, ModifierKeys.None, new Point(7, 8));

There are 2 ways to fix this issue. First, it is highly recommended to fix the accessibility (in this case UI Automation) of the tree item controls to associate unique properties to them. If you do not have access to the application sources and/or cannot rebuild the app, you might try differentiating the controls by adding some secondary properties such as “Instance”. In this case, you can add an Instance search property of value “2” to the UINotMyComputerTreeItem object.

    public class UINotMyComputerTreeItem : WpfTreeItem

    {

        public UINotMyComputerTreeItem(UITestControl searchLimitContainer) : base(searchLimitContainer)

        {

            #region Search Criteria

            this.SearchProperties[WpfTreeItem.PropertyNames.Instance] = "2";

            this.WindowTitles.Add("BasicForm");

            #endregion

        }
        …

    }

There is another non-trivial way to tweak your search property using the NextSibling search configuration as explained here.

4. Virtualization issues

An application could be designed in such a way that it’s UI objects are being fetched from a data source on demand basis. For example, say a grid table does not want to fetch all 10000 rows of data; instead it will just load the first 10 rows that show up in the view port and as and when the user scrolls the grid, it would load the rows from the data source. Playback of actions on these scrolled out rows will fail since there is no corresponding UI Object (and their accessible objects) existing at the time of search when the grid has just loaded and is at its initial state. The forum thread here has a mention of this issue.

To work around this, you would then need to evaluate the amount of scrolling required to get the target grid rows into view and insert explicit scroll actions in your test code such as Mouse.MoveScrollWheel() or any other Mouse APIs here on the scroll bar.

For certain UI technologies such as WPF which has virtualization support from accessibility layer (UI Automation), Coded UI Test playback does fine. Note that UIA virtualization support in WPF is provided for .NET4.0 and above. Hence, if you have a WPF application containing virtualized item containers built in .NET3.5 or below, you need to do one of the following:

  1. Recompile the application on .NET4.0 or above.
  2. Add an application configuration file (yourapp.exe.config) specifying the supported runtime, something like

<?xml version="1.0"?>

<configuration>

<startup>

<supportedRuntime version="v4.0"/>

</startup>

</configuration>

You might come across one playback issue related to WPF virtualization on nested containers such as a Datagrid inside a Tab Page. The blog here describes in detail the problem statement and the hotfix released over Visual Studio 2010 Service Pack 1.

5.  Hand coding search for expandable controls

If you are scripting the search hierarchy of a control which has expandable ancestors (for e.g. a multi-level tree view item), make sure that all the expandable ancestors have SearchConfiguration.ExpandWhileSearching added. (uiControl.SearchConfigurations.Add(SearchConfiguration.ExpandWhileSearching)). You need to worry about this if the search hierarchy is auto-generated by Coded UI Test; the recorder does this automatically.

6. Dealing with stale controls

SearchConfiguration.AlwaysSearch is another useful configuration when you want to be precisely sure that your playback is not picking up any cached UITestControl for search. Just to give some symptoms about playback failures where you would like to apply this configuration, a search for a control A inside a control X passed. Then the next action refreshed this control X and the subsequent action was search for a control B inside the same control X. Now control B has unique identifiable properties inside the sub-tree scope of X, yet the search for B still fails. This could be a case of some stale accessible objects not yet disposed of and the search for B is happening under the stale Control X reference.  In such a scenario, add an AlwaysSearch configuration to the Control X.

One word of caution: AlwaysSearch will have a performance hit in normal scenarios. Hence, do not include this configuration by default in your control search.

 

          
Troubleshooting playback action failures

 

1. FailedtoPerformActionOnBlockedControlException

One of the most common failure encountered is FailedToPerformActionOnBlockedControlException. Coded UI Test’s playback engine makes a best effort to get the target control into screen area and into the foreground prior to performing the action. So ideally no explicit “EnsureVisible” logic is required to be hand-coded into your test automation. However, accessibility issues in the application can cause failures otherwise.

When an action fails with this blocked control exception, visually verify if there is another control indeed that is blocking this control in the screen area. There could be instances of spurious popups not been dismissed or not handled in the test code. If the control appears to be in foreground, use an accessibility tool (say UISpy) to validate what is the actual control returned at that point in screen within the target control’s bounds. There could be possibility of transparent overlay controls that is actually blocking this control. In such situations, you might have to modify your test code to validate this and do absolute screen coordinates click on the control. The post here will be helpful. Alternately, you can search for similar issues reported in the MSDN forum related to FailedToPerformActionOnBlockedControlException.

2. UITestControlNotVisibleException

Verify (using an accessibility tool) that the control has a valid bounding rectangle. It could be an accessibility issue with the bounding rectangle implementation of the control itself.

3. Handling spurious popups

There has been queries in past on how to handle popups in the test code which are intermittent i.e. primarily, how to detect and dismiss the popups and continue with the next action. A quick search on the MSDN forum post here
will get your some useful answers related to this.

4. Recording Mouse Hovers

Non-recorded mouse hovers could be another reason behind blocked control exceptions. For plugins like IE, Coded UI Test records hovers on controls. However, for other technologies such as WPF, Silverlight, Winforms, etc, this information is not captured since the accessibility layer does not provide this level of information. Consider a scenario where a control ‘X’ has a OnMouseHover implementation that overlays another control ‘Y’ on top of it. So when the user hovers and clicks on the control, the Coded UI Test recorder will actually record a click on the control ‘Y’. During playback, the control ‘Y’ is obscured behind the control ‘X’ unless hovered upon explicitly.

To overcome this issue, you would need to record an implicit hover. In the codeduitestbuilder.exe.config file, you will find entries

    <!-- HoverKey to use. -->

    <add key="HoverKeyModifier" value="Control, Shift"/>

    <add key="HoverKey" value="R"/>

    <!--Use this to enable/disable recording of implicithovers.-->

    <add key="RecordImplicitHover" value="false"/>

Setting RecordImplicitHover to true, you can record a hover action by placing the Mouse cursor over a control and pressing {Control + R}. 

5. Resilience issues with mouse action

You might in rare in occasion hit an issue wherein the Mouse.Click() was actually successful but the control did not respond to the click (which typically it would otherwise). These could be some one-off resilience issue and cause would vary across different scenarios, so not completely known. Coded UI Test playback has in-built WaitForReady logic (to ensure that the control is actually ready to receive the next input) and UI synchronization mechanism (to ensure that the control’s window actually received the mouse (and keyboard) input). So the reason of control not responding could be something more than the input not reaching its destination window. First thing you can try out in such scenario is validate if any explicit introduced delay (such as Playback.Wait()) fixes the issue. If not, you may then try to raise the robustness level of WaitForReadyLevel to AllThreads ( by default it is UIThreadOnly). This could slow down the playback, so do not keep this setting as default.

              
Other playback issues

1. Search taking a huge amount of time

If the search is taking a lot of time to find the control, there could be the possibility that the recorder was not able to create an optimized search hierarchy.  Or you may have hand-coded your test automation script which is not optimized for search. There is a high chance that WaitForReady, MatchExactHierachy (a.k.a SkipIntermediateElements) and SmartMatch settings are related to this issue. Check the MSDN forum post here
to understand these better and apply them to your test code. The UITest logs will give a fair idea on which configuration setting needs to be tweaked to optimize the search (if at all there is a scope for it).

 2. Use WaitForReady settings judiciously

WaitForReady is inbuilt into the playback for a strong reason and has some default settings such as the WFR level and the WFR Timeout. At times though, you might need to raise the timeout value or the WFR level for applications which takes a huge amount of load. In the flip side, you might sometimes need to turn off WFR temporarily to speed up your playback. Ensure you know what you are doing with these WFR settings and apply it with caution. Also,
check out the section on “How to handle search failures because of slow page loading” here.

 3. Optimize your test code while fetching UITestControl item collection

A common mistake I’ve observed  among Coded UI Test users is something in the lines of

            WpfTable myTable = FindTable(…);

            for (int index = 0; index < myTable.RowCount; index++)

            {

                UITestControl row = myTable.Rows[index];

                // Do some action on the row.

            }

There is no caching built into the .Rows implementation. You are essentially re-fetching the entire row collection in each iteration. This has a huge performance hit. So avoid this by getting the UITestControlCollection
out of the loop.

 4. UITestControl.GetProperty failures

Coded UI Test provides the access to the control properties to the extent of what is provided by the accessibility layer.  First of all, if you encounter an issue where the property value obtained via Coded UI Test GetProperty()
is not what you are expecting, verify this control’s properties via an accessibility tool. Coded UI Test does not, in almost all cases, do any special processing over the value received. So it could be a genuine accessibility issue.

To extend support for additional properties fetching and validating, check out some of the blogs here: [1] [2] [3] . Another interesting blog on validating properties on nested Silverlight
controls can be found here.

5. Running playback outside a Coded UI Test method

Ensure that you are calling Playback.Initialize() and Playback.Cleanup() explicitly. Blog here describes this.

 

Troubleshooting recording failures

1. Unable to identify the control

Verify using an accessibility tool if it can identify the control. If it too does not, in all probability it is the lack of required accessibility implementation for the control. The blog series here
gives a good direction to extend the support. Another sequence of blogs here shows how to add support for 3rd party controls. And some more internals of the extensibility points are described here.

2. “Last action was not recorded because the control with Name ‘XXX' and ControlType 'YYY' does not have any good identification property”

You will typically hit this issue for data bound item controls which do not have ToString() implemented properly to disambiguate it from its siblings. The value returned from ToString() is what is being picked
up by default by the accessibility layer as the ‘Name’ property value. The blog here describes how to get automation working for data bound WPF list or combo box.

3.  “No Silverlight controls were detected. Verify that the application under test is built using Silverlight assemblies …”

Check out the MSDN documentation here to understand how to setup a Silverlight 4 application for test.

4 .Configuration options in recorder.

Keep note of settings in the codeduitestbuilder.exe.config file such as ThinkTimeThreshold and RecordThinkTime, AggregatorTimeout, ExcludeProcess and IncludeProcess. The options are self-explanatory in the configuration file and can be tweaked to address recording issues such as multiple actions not getting aggregated into a single actions, actions not getting recorded on certain application, etc.

 

The above mentioned points cover some of the common issues encountered and may not be totally exhaustive. There is scope to drill down to some more of the UI technology specific areas and collate the set of trouble
shooting measure. Meanwhile, I hope the above is useful to get starting and captures a good proportion of the issues which you can debug at your end. If there are still blockers, feel free to post your queries in the Coded
UI Test forum
and ensure you provide the following information that would greatly help in investigating the issue.

 
1. Describe your problem.

2. Mention what all troubleshooting measures you have already applied.

3. Create a minimal repro step. Huge logs and UIMap file just makes it difficult to debug.

4. Provide the log files. Check here on how to enable logging.

5. The recorded .uitest file, or better still, the minimal Coded UI Test project that you created.

6. Snapshots of the application to show the visual UI hierarchy would be very useful. Also, the UI hierarchy snapshot from accessibility tool such as UISpy, Inspect, etc.

7. Sample application is always helpful !