Fluent Bytes

"The only source of knowledge is experience" - Albert Einstein-

Maintainable Test automation for Winforms using CodedUI

This week I got a request on twitter how to work with CodedUI for windows forms and if I had any example. A couple of weeks ago, during a deep dive session we did in Sweden, I got more or less the same question on how can I access my controls when using windows forms, because we are having trouble getting CodedUI to work for us. So therefore I thought it would be a good idea to create a simple sample and describe in a bit more detail how to approach this.

If you have looked at my PluralSight courses or attended one of the training events where I teach CodedUI, you might know that I am trying to convince everyone to never use the CodedUI test recorder, since the way it tries to locate controls and the way it saves the information in the recording file is a nightmare to maintain.

So when investigating how we can locate controls in windows forms in a maintainable way I also avoid the recorder and just use the CodedUI object model to find the controls I need. So let’s first dive into how to find controls and then look at how to write maintainable UI Automation code.

So how can we locate controls in Windows forms applications?

First of all you need to search for controls by using the Search Control classes specific for Windows Forms applications. You will find these in the Microsoft.VisualStudio.TestTools.UITesting.WinControls namespace. You use the search properties on the control to define how CodedUI needs to search for the control.

So let’s have a look how we can locate different UI controls based on the following example application. Let’s start with a Search for the button that is shown in the form here below?

clip_image001

First of all we need to know what the properties of this button are. If you look at how we develop windows forms applications then it is very common that the developer provides a name for the control in code, because they need to access them in code. You also see this button has a title “Click me!”

The properties for this button look as follows:

clip_image002

If you want to search for this control in a maintainable way, you always try to avoid taking any dependencies on the look and feel of the control you search for. So taking a dependency on the text on the button is generally not a smart thing to do. This would also cause issues when you have e.g. multi language versions of your application.

So we want find the control preferably on the name the developer gave the control. Since that name will probably not change. Reason is that this name is also used in code for referring to the control.

So we want to find the control based on the programmatic name. The question is, is this possible?

clip_image003

To identify how to search for a control, you can use the test recorder tool to inspect the properties of the control when we run the application.

The inspection of the control looks as shown in this screenshot on the side.

Here you can see that we can search on the programmatic name of the control by using the search property Name of the control.

So based on this information you would expect you would be able to find the control based on the following code:

 

 

But when you run this test you will see the test fails and is unable to locate the control.

It took me a while to figure out, but apparently every control can be found by first searching for a WinWindow control that has the name of the control and then within that window search for the control.

Normally I use a tool, called Spy++ to find controls in the UI. This tool has been in the C++ SDK for years and something I always used. But when you look with Spy++ you will see the control Hierarchy is the same as you would expect from the UI perspective.

I got some help from Abhitej John who is a software engineer at Microsoft who works on the CodedUI tools. When I told him that I did not understand the hierarchy of the controls he told me the following:

“Coded UI for Windows forms works on IAcessible objects. The hierarchy that is defined by this native element (in coded UI terms) is what we use to search for controls. The tool that you would use in comparison to look at the hierarchy is “inspect” in MSAA mode. Spy++ is a UIA based tool that identifies WPF controls. Hence you see that difference in hierarchy”

So I used the tool he suggests that I could find on my machine at the following location:
<install drive>:\Program Files (x86)\Windows Kits\8.1\bin\x86\Inspect.exe

controlhierarchy

When looking at the form using this tool you can see that when you set it in MSAA mode, you see the hierarchy is different and that is the reason we need to use a slightly different approach to find our controls.

So that looks like follows for e.g. the button:

 

This works for all the controls in the same way. You always search for a WinWindow that has the name of the control. then inside that window you search for the control of the type you expect.

Now don’t make the mistake I did to search inside the WinWindow for the control, including the search properties, because that will result in the dreadful message:

“Another control is blocking the control. Please make the blocked control visible and retry the action.”

Alternatives with AccessibleName

An alternative way that also works is setting the AccessibleName of the control. if you set this value, then you don’t need the containing WinWindow control and you can search straight for the control based on the name and the type you expect. But this has a nasty side effect that is probably not visible immediately.

AccessibleName is used for accessibility tools. It provides the name of the control. You can check this by e.g. starting windows Narrator on your machine and the moment you click a control it will tell you which control you are accessing on that particular form. Now when we change the name of the accessible name, then we can introduce issues with our application in production when we have people that rely on these names to represent something they can understand.

So therefore it is best to search based on the control name, without tweaking the AccessibleName property.

How can we make the test better maintainable?

As I have discussed in al my courses, the best way to ensure you create a maintainable set of UI Automation functions is by adopting the concept of writing DAMP tests. DAMP stands for Descriptive And Meaningful Phrases and you use this to ensure you can read the scenario from your tests straight from the code.

You do this by abstracting the UI by using a Page Object Abstraction. For each functional part of your UI you create a class that abstracts the actions of the UI and provides methods you can call. Each method returns a Page Object that contains the next actions available in the UI. this then results in a nice Fluent API that you can use to write your test scenario.

So for clicking all controls in the UI the test scenario would look like this:

 

I hope you agree that this is way more readable then the test I showed before, where I only clicked one button. Imagine the clutter you get when you click multiple elements in the test.

Page object pattern

So the way you write the methods in the Page Object abstraction is by creating a class MainForm and adding action methods in that class that interact with the UI as follows:

 

Now you see the actual search is now abstracted in the MainForm page class and my test now delegates the actual interaction with the controls to that instance of the class. By returning the MainForm instance as result of the method, you get the possibility to call the next method, resulting in the fluent API

Conclusion

We have looked at how to find controls in a windows forms application and found that we need to search for a WinWindow control first before we can find the actual control we want to interact with. Secondly I showed how you can abstract the interaction using a pattern called the Page Object Pattern, that enables us to write better maintainable code.

You can download the full sample I have from this location: http://bit.ly/CodedUISample

Just unzip it and run it in your visual studio IDE. The only thing you need to change is the launch path for the application, since that will be depending on where you unzipped the solution

Hope this helps

CTO at Xpirit, Microsoft Regional Director, Visual studio ALM MVP, Speaker, Pluralsight Author and IT Architect Consultant

13 Comments

  1. Giorgio Di Nardo

    March 21, 2016 at 10:09 am

    Hi Marcel.
    Thanks for your great (as usually) job.
    I have tried your example. It works for me on Win 8.1 with VS 2013, but it does not on W10 with VS2015. I think something changed in the way in which controls hierarchy is build on W10 and, as an addition, everything seems shifted on the screen, so when you ask to Mouse.Click a specific control, it clicks in a different place.
    Do you know if there are known issues with W10?
    Thanks, Giorgio.

    • I will look into it and post back when I know more

      • Hi Marcel,
        Excellent post. I am facing the same issue as Giorgio with CodedUI on W10 with VS2015. Did you ever get to look into this? I found that if I switch Inspect.exe to UI Automation, shifting is gone and everything seems to be aligned properly. I am not sure how I can get coded UI to use UI Automation for WinForms based application as opposed to the default MSAA.
        Any help would be greatly appreciated.
        Thanks,
        GK

        • unfortunately I have not looked into this. the problem I face is that I can’t reproduce the issue on my machines and I tried multiple.
          Are you able to record a short screen capture on what is going on and then also provide me with the info on how the screen resolution of your system is set up? send it to me in the mail to vriesmarcel@hotmail.com and then I will try to reproduce it again and see if I can find a solution.

        • You can tell CodedUI to explicitly search using UI Automation by doing the following:

          WinButton myButton = new WinButton(myContainer);
          myButton.TechnologyName = “UIA”

          Mouse.Click(myButton);

          CodedUI doesn’t search for the control until we perform an action on it so just be sure to set the TechnologyName property before interacting with the control.

  2. Hi Marcel,
    I’m trying to create UI application that will select the specific tests to run.
    When calling the test from a “button_Click” method, I always get an error that the control was not found.
    What is the best way to do it?
    I tried the following:
    1. Create the application in a different solution and add as reference the coded UI library project with all the controls
    2. Create the application in the same project that the tests and controls are placed.
    I have used Hand UI coded for the controls and for creating the tests.

    Thanks in advanced,
    TB

  3. Marcel, I have studied your CodedUi course on Pluralsite.
    I am building against a Wpf application. It is complex and runs in an enterprise environment. We will be using TeamCity once it it ready.
    I want to handcode this completely.
    As we have multiple wpf applications on the production floor, I want to build my first project out using the best of SOLID practices from the start. (including extension metthods and base classes to abstact out eventually to a nuget package, as well as fluent methodology)
    I am comfortable with all of that.
    However, still stumbling over design.
    Do you have a fully matured WFP project that would include all the best practices , file and project structure that you would use . I keep finding resouces that are web or window from others that has only mixed me up.

    If you have something out on github that I could use as a model, I would deeply appreciate looking at it. Thanks

    • You Demo with PageObjects Code First is helpfull, but am hoping I could look at something in Wpf instead of web. Thanks

      • I am sorry I don’t have a demo for that laying around. But the basic principles are the same. Define the functional area’s of your application and build a page object for each part. Make them nice and small and compose the flow out of the chaining of the objects.

    • Unfortunately I don’t have a good sample for this at the moment. I would love to help out, but this then needs to be in a consulting way, since I don’t have any representative WPF application that I can base the help on

  4. Marcel, Running test ClickButton1 runs fine (passed test). Running test TestFormWithPageObject fails with the error you mentioned earlier, “Another control is blocking the control. Please make the blocked control visible and retry the action.” I assumed both tests should pass as written. What do I need to do to make TestFormWithPageObject pass?

    Copy of error:
    Test Name: TestFormWithPageObject
    Test FullName: WinformsCodedUI.UITests.CodedUITest1.TestFormWithPageObject
    Test Source: C:\repos\Demos\WinformsCodedUI\WinformsCodedUI.UITests\CodedUITest1.cs : line 76
    Test Outcome: Failed
    Test Duration: 0:00:07.2404499

    Test method WinformsCodedUI.UITests.CodedUITest1.TestFormWithPageObject threw exception:
    Microsoft.VisualStudio.TestTools.UITest.Extension.FailedToPerformActionOnBlockedControlException: Another control is blocking the control. Please make the blocked control visible and retry the action. Additional Details:
    TechnologyName: ‘MSAA’
    Name: ‘Click me!’
    ClassName: ‘WindowsForms10.BUTTON’
    ControlType: ‘Window’
    —> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0xF004F003

  5. Hi Marcel,
    I am impressed with your web site contents with examples. This specific CODEDUI on WinForm example put me more interest to work on it. I have a winform with Infragistics Combobox on it and the combobox datasource is filled with datatable with 2 columns (ID and Desc). I tried a lot to create a test method and the combox should pick one of the item from the dropdown. I failed in making this through the codedUI c# script. Can you help me on this in how to achieve it?
    var custtype = new WinWindow(dfcol[3]);
    custtype.SearchProperties.Add(WinWindow.PropertyNames.ControlName, “ucCusType”);
    var custtypecol = custtype.GetChildren();

    var custtypecb = new WinComboBox(winform);

    WinControl wctrl = new WinControl(custtypecb);
    wctrl.SearchProperties[UITestControl.PropertyNames.Name] = “Open”;
    wctrl.SearchProperties[UITestControl.PropertyNames.ControlType] = “DropDownButton”;
    wctrl.WindowTitles.Add(“XXXXXXX”);
    //wctrl.SearchConfigurations.Add(SearchConfiguration.ExpandWhileSearching);
    string lname = “RED”;

    int k = 0;
    foreach (WinListItem wlt in custtypecb.Items)
    {
    if (wlt.DisplayText == lname)
    {
    itm = wlt;
    break;
    }
    k++;
    }
    if (itm != null)
    {

    custtypecb.Expanded = true;

    itm.Select();
    //Mouse.Click(itm);

    //wctrl.WaitForControlEnabled();
    //wctrl.SetFocus();
    //Mouse.Click(wctrl);
    // Mouse.Click(itm);

    }

    ALL the time I get the playbackfailureexception cannot setproperty with value RED.

1 Pingback

  1. Coded UI | Vincent

Leave a Reply

Your email address will not be published.

*

© 2017 Fluent Bytes

Theme by Anders NorenUp ↑