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 = @"C:\Users\...\AppiumTest.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?

6 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

Please login or register to post comments.