owenG
home learn tableau about
divider
SDLC VS 2010 Coded UI Test Coded UI Test and Fitnesse MSBuild 4.0 MSBuild and IronPython MSBuild and IronPython - TFS checkins MSBuild and IronPython - Custom SQL Data








previous next

Coded UI Walkabout Part 3

Testing the Test

The test case so far may seem to be adequate but further exploration of the generating code reveals potential problems with 'true test' vs. 'expected test'. First avenue for investigation is within the UIMap.uitest for this project. By default there is only one of these map files and you cannot simply right-click and rename in order introduce distinct filenames. It is possible to create multiple UIMap files though, which would certainly help with even moderately complex applications or websites. The .uitest is stored in XML format and editing the file manually, without using the Test Builder, probably isn't the best idea in most cases simply due to the complexity and general inscrutability of the XML structure. But for very minor tweaks it looks to be perfectly doable, with the caveat that the UIMap.Designer.cs code will need to be regenerated after manual edits. This re-generation can be done on-demand by opening the Test Builder and pressing the Generate Code icon (without needing to have actually done anything else) followed by clicking the Generate button on the resulting pop-up. This is another case in which MS may have a power tool in the future that allows for true editing and provides a real UI on top of the XML within UIMap.uitest. Hopefully said functionality will be rolled into a future service pack or release.

The particular XML snippet I want to look at more closely in my test relates to the definition for that first hyperlink control. The Test Builder gave it an ID of UIOwenGhomeowenGnetHyperlink and that is how it will be referenced in the C# code, as the last descendant in a path of nested controls. Once a control has selected with the crosshairs tool the Test Builder makes available a panel that displays the tree structure of the UI Map in an easy to navigate manner. Assuming a control has been added and saved in the UIMap.uitest file, another way of getting a handle on heirarchy for the control is to open the UIMap.uitest in a visual XML editor like XML Notepad (available as a free download from Microsoft). There are two parent sections w/in the UIMap that are worth exploring from an end-coder's point of view, ExecuteActions and Maps->UIMap. For the current purpose of learning more about the control definitions, as opposed to what actions are actually being automated, UIMap is the place to go.

Within XML Notepad, I press Ctrl+F to run a simple search for "Hyperlink", since that is the type of control I'm looking for and this UIMap is quite simple. For more complex searches, XML Notepad does support XPath syntax.

Find Hyperlink in UIMap node

The Find function here searches from the top of the file but the only hits to pay attention to are those in Maps/UIMap, specifically where a UIObject element has a ControlType attribute with value = "Hyperlink".

Hyperlink Control located

The text on the right pane can be used to discover the full path to hyperlink UIObject, where the Descendants of a given TopLevelWindow can be concatenated by their Id's in order to get the full object heirarchy.

TopLevelWindow: UIOwengGoogleSearchWinWindow
Descendants: UIOwengGoogleSearchDocument -> UIRsoCustom -> UIOwenGhomeowenGnetHyperlink
The hyperlink in question can be referenced in partial UIMap.cs as this.UIOwengGoogleSearchWinWindow. UIOwengGoogleSearchDocument.UIRsoCustom.UIOwenGhomeowenGnetHyperlink.

Once we have a particular UI element, it may be more helpful to look at the raw XML in .uitest:

XML
<UIObject ControlType="Hyperlink" Id="UIOwenGhomeowenGnetHyperlink"
         FriendlyName="owenG - home | owenG.net" SpecialControlType="None">
  <TechnologyName>Web</TechnologyName>
  <WindowTitles>
    <WindowTitle>oweng - Google Search</WindowTitle>
  </WindowTitles>
  <AndCondition Id="SearchCondition">
    <AndCondition Id="Primary">
      <PropertyCondition Name="ControlType">Hyperlink</PropertyCondition>
      <PropertyCondition Name="Id" />
      <PropertyCondition Name="Name" />
      <PropertyCondition Name="TagName">A</PropertyCondition>
      <PropertyCondition Name="Target" />
      <PropertyCondition Name="InnerText">owenG - home | owenG.net</PropertyCondition>
    </AndCondition>
    <FilterCondition Id="Secondary">
      <PropertyCondition Name="AbsolutePath">/</PropertyCondition>
      <PropertyCondition Name="Title" />
      <PropertyCondition Name="Href">http://www.oweng.net/</PropertyCondition>
      <PropertyCondition Name="Class">l</PropertyCondition>
      <PropertyCondition Name="ControlDefinition">class=l onmousedown="return rwt(this,'',</
            PropertyCondition>
      <PropertyCondition Name="TagInstance">1</PropertyCondition>
    </FilterCondition>
  </AndCondition>
  <SupportLevel>0</SupportLevel>
  <Descendants />
</UIObject>

I'm looking to see how the test decides which object represents the hyperlink I clicked on. For non-web elements, the test engine looks to see which controls match all of the (Microsoft.VisualStudio.TestTools.UITesting. UITestControl).SearchProperties that have been defined for the candidate control. For a control-search that has not been modified i.e. the search pattern is defined purely in the UIMap.uitest and not with any custom C# in UIMap.cs, this should match the list of property/value combinations under SearchConditions->Primary in the .uimap. If web controls are involved, the SearchProperties remain the primary search pattern. Then, if no control matches ALL of the SearchProperties, the (Microsoft.VisualStudio.TestTools.UITesting.UITestControl). FilterProperties are added to the search criteria. The FilterProperties are searched from beginning to end and once a hit happens in ANY of items, that control is returned as the 'found' one. The FilterProperties property/value collection appears to match up with the PropertyCondition's listed under <FilterCondition Id="Secondary">. See the blog of Balachander G. Subramaniam for more details on how CUIT finds controls, posting on 28Dec2009.

Having reviewed the actual XML content, it now appears that there are a few problems with the test. From one point of view, the first thing to look at may be the presence of the InnerText key. Since it is a member of the SearchProperties, the value must match the string (case-insensitive) "owenG - home | owenG.net" exactly (SearchProperties = AND search on each item to match, FilterProperties = OR search over all items to match). But what I really care about is that the link is to a page somewhere in my domain. If something changes in the algorithm Google uses to return hits, it is quite possible that a Google search for "oweng" will result in the first result hyperlink pointing to the About page. In that case the InnerText it searches for is still "owenG - home | owenG.net" but that value on the first link will be "About Owen Galvin | owenG.net". The CUIT engine would skip over that page and perhaps fail to find any matching controls on the results page. My test oracle though, was that some page in oweng.net be returned as the first hit, not necessarily the home page. So now I'll look into modifying the SearchProperties via C#.

Open up the UIMap.cs, note that it is a partial class, with the other part being UIMap.Designer.cs. That latter file is auto-generated by the test engine and shouldn't be modified since any changes will be lost once the Test Builder gets involved again. Instead, customization code generally gets written in UIMap.cs. I'll add a simple method to remove the InnerText portion of the search pattern:

C#
    public partial class UIMap
    {
        public void RemoveInnerLinkTextForOwengHyperlink()
        {
            this.UIOwengGoogleSearchWinWindow.UIOwengGoogleSearchDocument.UIRsoCustom.
                UIOwenGhomeowenGnetHyperlink.SearchProperties.Remove("InnerText");           
        }
    }

The above reference to InnerText property could have been written using the PropertyName equivalent, which in this case is exactly the same. Following this route does allow Intellisense to help out however:

C#
    public partial class UIMap
    {
        public void RemoveInnerLinkTextForOwengHyperlink()
        {
            this.UIOwengGoogleSearchWinWindow.UIOwengGoogleSearchDocument.UIRsoCustom.
                UIOwenGhomeowenGnetHyperlink.SearchProperties.Remove
                    (HtmlControls.HtmlAreaHyperlink.PropertyNames.InnerText);           
        }
    }

To get the above working as-written in my environment I needed to add a

C#
    using HtmlControls = Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;

alias since otherwise VS was requiring I use the fully qualified path to the HtmlControls object when referencing it in code.


The hyperlink definition matches its heirarchy as found in the UITest.uimap file. When working in Visual Studio it is usually easiest to simply hit "UI" when navigating the to child controls via Intellisense. Most objects in a given path are of type UITestControl and will implement all of the expected methods and properties

UITestControl raw

but it looks like the descendant controls will be prefaced with the text "UI".

UITestControl .U

Next, more customization...

previous next