UI Automation: Moving from CodedUI to Appium

WinForms Team Blog
25 November 2019

In its release notes for Visual Studio 2019, Microsoft announced the end of life for Coded UI test.

OSS UI test tools such as Selenium and Appium have gained momentum and have a strong community backing. Because these frameworks have become industry standards, we deprecated Coded UI test for automated UI-driven functional testing. Visual Studio 2019 will be the final version of Visual Studio with Coded UI test features.

Microsoft recommends Appium with WinAppDriver for testing desktop and UWP apps, and this message has sparked the interest among our users: are DevExpress controls compatible with Appium? We have tested a number of our controls, and the short answer is - yes. Here’s what you should do to create automated UI tests with Appium.

  1. Go to https://github.com/Microsoft/WinAppDriver/releases and download two applications.

    • WinAppDriver - allows you to run tests. Requires installation.
    • WinAppDriver UI Recorder - allows you to record tests at runtime. Does not require installation - unzip the downloaded archive to any folder.
  2. Turn on Developer Mode within Windows.

  3. Run WinAppDriver.exe as an administrator and leave it running. Note the address the application is listening to, you will need it later.

  4. Open a Visual Studio solution that you want to test, or create a new sample solution.

  5. Add a new Unit Test Project to the solution.

  6. Right-click the Unit Test project in Solution Explorer and select “Manage NuGet Packages…”. Install the latest stable Appium.WebDriver package.

  7. Open the UnitTest1.cs file of the Unit Test project and add two classes: MainDemoSession (defines methods that start and finish test sessions) and Helper (contains the method that finds tested UI elements). Use the address from step #3 as the WindowsApplicationDriverUrl value.

     public class MainDemoSession
     {
         protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
         private const string ApplicationPath = @"...\your_solution_folder\Project.exe";
    
         protected static WindowsDriver<WindowsElement> desktopSession;
    
         public static void Setup(TestContext context)
             {
                 // Launch a new instance of the tested application
                 if (desktopSession == null)
                 {
                     // Create a new session to launch the tested application
    
                     AppiumOptions options = new AppiumOptions();
                     options.AddAdditionalCapability("app", ApplicationPath);
                     desktopSession = new WindowsDriver<WindowsElement>(
                         new Uri(WindowsApplicationDriverUrl), options);
                     Assert.IsNotNull(desktopSession);
                     Assert.IsNotNull(desktopSession.SessionId);
    
                     // Set implicit timeout to 1.5 seconds
                     //to make element search to retry every 500 ms
                     //for at most three times
                     desktopSession.Manage().Timeouts().ImplicitWait =
                         TimeSpan.FromSeconds(1.5);
                 }
             }
    
         public static void TearDown()
             {
                 // Close the application and delete the session
                 if (desktopSession != null)
                 {
                     desktopSession.Close();
                     desktopSession.Quit();
                     desktopSession = null;
                 }
             }
     }
    
     public static class Helper
     {
         public static WindowsElement FindElementByAbsoluteXPath(
             this WindowsDriver<WindowsElement> desktopSession,
             string xPath,
             int nTryCount = 3)
         {
             WindowsElement uiTarget = null;
             while (nTryCount-- > 0) {
                 try {
                     uiTarget = desktopSession.FindElementByXPath(xPath);
                 }
                 catch {
                 }
                 if (uiTarget != null) {
                     break;
                 }
                 else {
                     System.Threading.Thread.Sleep(400);
                 }
             }
             return uiTarget;
         }
     }
  8. Modify the auto-generated UnitTest1 class as follows:

     [TestClass]
     public class UnitTest1 : MainDemoSession
     {
         [TestMethod]
         public void TestMethod1()
         {
           //test start
    
           //test finish
         }
         [ClassInitialize]
         public static void ClassInitialize(TestContext context)
         {
             Setup(context);
         }
    
         [ClassCleanup]
         public static void ClassCleanup()
         {
             TearDown();
         }
     }
  9. Run your application, and (in case you have a multi-screen setup) drag it to the main system display.

  10. Launch the WinAppDriver UI Recorder and click “Record”. Hover over the first UI element you want to interact with, and wait until it starts flashing blue. The Recorder’s status bar will change its text from “Active” to “XPath Ready”.

  11. When the element is flashing, the recorder is ready and you can perform UI actions: click this element, drag it, enter new values, etc. After you are done with this element, hover over another UI element, wait for the recorder’s confirmation and repeat the process.

  12. Once you have recorded a sequence of steps you wish to reproduce, click “Pause” within the recorder. You can open the actions selector to make certain that all UI actions have been recorded.

  13. Click the “Generate and copy C# code to Clipboard” button to copy the code for all recorded actions. Paste this code into the UnitTest1.TestMethod1 method. For instance, the code below selects the “Job” tab.

    [TestMethod]
    public void TestMethod1()
    {
        //test start
        // LeftClick on TabItem "Job" at (20,31)
       Console.WriteLine("LeftClick on TabItem \"Job\" at (20,31)");
       string xpath_LeftClickTabItemJob_20_31 = "/Pane\[@ClassName=\"#32769\"\][@Name=\"Desktop 1\"]/Window\[starts-with(@AutomationId,\"XtraForm\")]/Pane[@Name=\"The XtraLayoutControl\"\][starts-with(@AutomationId,\"dataLayoutControl\")]/Table[@Name=\"Root\"]/Table[@Name=\"autoGeneratedGroup0\"]/Table[@Name=\"Root\"]/Table[@Name=\"Photo\"]/Table[@Name=\"FirstAndLastName\"]/Tab[@Name=\"Tabs\"]/TabItem[@Name=\"Job\"]";
       var winElem_LeftClickTabItemJob_20_31 = desktopSession.FindElementByAbsoluteXPath(xpath_LeftClickTabItemJob_20_31);
       if (winElem_LeftClickTabItemJob_20_31 != null)
       {
          winElem_LeftClickTabItemJob_20_31.Click();
       }
       else
       {
          Console.WriteLine($"Failed to find element using xpath: {xpath_LeftClickTabItemJob_20_31}");
          return;
       }
       //test finish
    }
    
  14. During internal testing, we observed that auto-generated code may fail to locate the UI element by its full path:

    /Pane\[@ClassName=\"#32769\"\][@Name=\"Desktop 1\"]/Window[starts-with…

    If this happens, shorten all element paths so that they begin with “/Window”.

    string xpath_LeftClickTabItemJob_20_31 = "/Window[starts-with(@AutomationId...";

    Additionally, you can use Assert.Fail instead of Console.WriteLine to debug the test (should it fail to locate a UI element).

    Assert.Fail($"Failed to find element...");
  15. Right-click the Unit Test project in Visual Studio and click “Run Tests”. The test will launch your application, repeat all recorded steps, and close the application afterwards. All test activity is logged in the WinAppDriver console launched in step #3.

You can launch Appium tests in much the same way as Coded UI. The only difference is that you need the WinAppDriver running on your test execution machine.

Tell us what you think

With Microsoft's decision to deprecate Coded UI support, what is the future of automated UI tests for you and your enterprise? How many UI automation tests your current project has? Will you migrate them to Appium, or will you switch from UI automation in favor of more unit tests?

What’s New in v20.1

To explore the scope, breadth and capabilities of our new products/features, please visit: https://www.devexpress.com/Subscriptions/New-2020-1.xml.
9 comment(s)
Blago Culjak
Blago Culjak
Hi Dmitry, I have tried using Appium with DX Ribbon Window, but Recorder just doesn't hit Ribbon Tab as it's recorded. Don't know why..
26 November 2019
Blago Culjak
Blago Culjak
Maybe the problem is that I have Login window and after that RibbonWindow and Appium doesn't attach to it...
26 November 2019
Dmitry (DevExpress)
Dmitry (DevExpress)
Hi Blago, thank you for the question. This post illustrates how to create Appium automation UI tests for WinForms application. According to your recently submitted Support Center ticket, you are using our WPF controls that do not officially support UI automation tools.
27 November 2019
Blago Culjak
Blago Culjak
Hi Dmitry, do you plan to add WPF UI automation test support?
27 November 2019
Ernie Salazar
Ernie Salazar
Like Blago, I would like to know if WPF will be supported by the DX controls as well.
3 December 2019
Alex Chuev (DevExpress)
Alex Chuev (DevExpress)

Blago and Ernie,

We are going to discuss the UI Automation testing support in our upcoming roadmap for 2020. In short, you can create UI Automation tests for basic scenarios, but more complex cases may require custom code. We are looking for more feedback from developers before we commit to full UI Automation testing support. If you would like to share additional info about your test protocols,  please feel free to contact me at wpfteam@devexpress.com.


P.S. Here is a link to the Support Center ticket that Dmitry mentioned:
https://www.devexpress.com/Support/Center/Question/Details/T836146/ui-testing-ribbon-window-that-open-up-from-main-window

Thanks,

Alex

4 December 2019
Chris Goedde
Chris Goedde
Do you have any samples that work with a data grid?  Specifically how to tell which row or cell in the grid is selected.  I am already trying to convert our Coded UI code to using Appium.  Most things are going well.  The grid is my hangup so far.  There is a Selected property, but that is always coming back False for me.
12 December 2019
Customer123159
Customer123159
Hello, Dmitry and Alex Chuev !

Thank you for your great support. 

I second Chris Goedde: it would be really nice if we DevExpress users, could have samples with data grids to learn from. 

A great 2020 for everybody.

All the best,
Hilton
7 January 2020
Eugene Elder
Eugene Elder

2020 Roadmap team,

I have nearly 100 tables in my DevExpress app. Given the size of my application, automated testing is really important. I have tried on 2 prior occasions a few years ago to use the scripting language from WinBatch.com to build testing scripts but I ran into issues with the naming convention of the DevExpress UI objects. I am glad to hear there is a chance that I might get another stab at implementing an automated testing solution. We are moving from Monday.com to DevOps boards and I want to embrace Azure Test plans and the other features of DevOps.

(This is all new to me.) My vote is that you work toward a solution that gives me the power to record a test pattern and then change the script it recorded by add conditional code to the script. Take a brief look at WinBatch and notice the power of its scripting language. It's like programming a data entry robot that is expecting things to go wrong and having conditional code to handle the different scenarios. It also allows me to email, text and communicate with all of Window's devices.

25 April 2020

Please login or register to post comments.