Data driven UIDs for automated WPF UI testing

The Ultimate and Premium versions of Visual Studio 2010 include a new set of tools for creating automated tests that interact with application UI known as Coded UI Tests. One of the tools is a recorder that will generate the appropriate code for you as it monitors your interactions with your application.

Although it is based on older mechanisms for examining the UI (it makes me yearn for the clarity of Snoop), it is still effective at identifying most WPF interactive controls in simple applications. Problems start to arise when working with the more complex data-driven type of applications where WPF excels.

The root of the problem is how Coded UI Tests identify a specific control. Multiple options can be used depending on the scenario including blind X-Y coordinate selection, Name searching, and Automation ID searching. Although X-Y locations generally break down quickly with WPF dynamic layouts, Name and Automation ID are easy to set from XAML as x:Name/Name and x:Uid/Uid respectively.

Assigning a specific Uid works great for a single button instance (and can even be done for you automatically with updateuid), but not so much for things like data-bound ItemsControls with Buttons inside their ItemTemplate. A standard Uid will show up the same on each instance, requiring additional search criteria in order to locate the right button (Coded UI Test will allow searching by an index as well but this is still fragile and can be tedious).

Fortunately Uids don’t always need to be static values in XAML. If you’ve ever tried to set a Binding on a Uid you might disagree, as will the compiler, but this restriction only applies for normal XAML blocks. Uid properties inside templates will allow a Binding to be assigned to them and generate an appropriate value at run-time. This allows the Uid to actually contain unique attributes of the data that can make it easy to target a control for a specific piece of data and have the Coded UI Test continue to locate the correct control even if the collection data changes in other ways.

Here’s an example of some simple bound Uids made up of a string and a couple data values:

    <ItemsControl ItemsSource="{Binding DataList}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <TextBlock Text="{Binding Id}" Margin="5"/>
                    <Button Content="{Binding Action}" DockPanel.Dock="Right">
                        <Button.Uid>
                            <MultiBinding StringFormat="Button{0}_{1}">
                                <Binding Path="Id"/>
                                <Binding Path="Name"/>
                            </MultiBinding>
                        </Button.Uid>
                    </Button>
                    <TextBox Text="{Binding Name}">
                        <TextBox.Uid>
                            <MultiBinding StringFormat="Text{0}_{1}">
                                <Binding Path="Id"/>
                                <Binding Path="Name"/>
                            </MultiBinding>
                        </TextBox.Uid>
                    </TextBox>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>