Enable coded UI testing of your controls

Applies to: yesVisual Studio noVisual Studio for Mac

Note

This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

Implement support for the coded UI testing framework to make your control more testable. You can add increasing levels of support incrementally. Start by supporting record and playback and property validation. Then, build on that to enable the coded UI test builder to recognize your control's custom properties. Provide custom classes to access those properties from generated code. You can also help the coded UI test builder capture actions in a way that is closer to the intent of the action being recorded.

!Diagram showing how classes in ChartControl are extended through the CreateAccessabilityInstance class to classes in ChartControlExtensionPackage.](../test/media/cuit_full.png)

Note

Coded UI Test for automated UI-driven functional testing is deprecated. Visual Studio 2019 is the last version where Coded UI Test will be fully available. We recommend using Playwright for testing web apps and Appium with WinAppDriver for testing desktop and UWP apps. Consider Xamarin.UITest for testing iOS and Android apps using the NUnit test framework. To reduce the impact on users some minimum support will still be available in Visual Studio 2022 Preview 4 or later.

Support record and playback and property validation by implementing accessibility

The coded UI test builder captures information about the controls that it encounters during a recording and then generates code to replay that session. If your control doesn't support accessibility, then the coded UI test builder captures actions (like mouse clicks) using screen coordinates. When the test is played back, the generated code issues the actions in the same screen coordinates. If your control appears in a different place on the screen when the test is played back, the generated code will fail to perform the action. By not implementing accessibility for your control, you might see test failures if the test is played back on different screen configurations, in different environments, or when the UI layout changes.

Screenshot of the recording window in the coded UI test builder. The Pause button is highlighted and Click 'ChartControl' client appears in a tool tip.

If you implement accessibility, the coded UI test builder uses that to capture information about your control when it records a test. Then, when you run the test, the generated code will replay those events against your control, even if it's somewhere else in the user interface. Test authors can also create asserts using the basic properties of your control.

Screenshot of the recording window in the coded UI test builder. The Pause button is highlighted and Click 'A' label appears in a tool tip.

To support record and playback, property validation, and navigation for a Windows Forms control

Implement accessibility for your control as outlined in the following procedure, and explained in detail in AccessibleObject.

Diagram of classes in ChartControl showing the relationship between CreateAccessabilityInstance and the ChartControl.CurveLegend class.

  1. Implement a class that derives from Control.ControlAccessibleObject, and override the AccessibilityObject property to return an object of your class.

    public partial class ChartControl : UserControl
    {
        // Overridden to return the custom AccessibleObject for the control.
        protected override AccessibleObject CreateAccessibilityInstance()
        {
            return new ChartControlAccessibleObject(this);
        }
    
        // Inner class ChartControlAccessibleObject represents accessible information
        // associated with the ChartControl and is used when recording tests.
        public class ChartControlAccessibleObject : ControlAccessibleObject
        {
            ChartControl myControl;
            public ChartControlAccessibleObject(ChartControl ctrl)
                : base(ctrl)
            {
                myControl = ctrl;
            }
        }
    }
    
  2. Override the accessible object's Role, State, GetChild and GetChildCount properties and methods.

  3. Implement another accessibility object for the child control and override the child control's AccessibilityObject property to return the accessibility object.

  4. Override the Bounds, Name, Parent, Role, State, Navigate, and Select properties and methods for the child control's accessibility object.

Note

This topic starts with the accessibility sample in AccessibleObject, and then builds on that sample in the remaining procedures. If you want to create a working version of the accessibility sample, create a console application and then replace the code in Program.cs with the sample code. Add references to Accessibility, System.Drawing, and System.Windows.Forms. Change the Embed Interop Types for Accessibility to False to eliminate a build warning. You can change the project's output type from Console Application to Windows Application so that a console window doesn't appear when you run the application.

Support custom property validation by implementing a property provider

After you implement basic support for record and playback and property validation, you can make your control's custom properties available to coded UI tests by implementing a UITestPropertyProvider plug-in. For example, the following procedure creates a property provider that allows coded UI tests to access the State property of the chart control's CurveLegend child controls:

Screenshot of the coded UI test builder main window partially covered by an Add Assertions window with the State property of a Text control selected.

To support custom property validation

Diagram of classes in ChartControl and ChartControlExtension with the ChartControlExtensionPackage and ChartControlIPropertyProvider classes highlighted.

  1. Override the curve legend accessible object's Description property to pass rich property values in the description string. Separate multiple values with semicolons (;).

    public class CurveLegendAccessibleObject : AccessibleObject
    {
        // add the state property value to the description
        public override string Description
        {
            get
            {
                // Add ";" and the state value to the end
                // of the curve legend's description
                return "CurveLegend; " + State.ToString();
            }
        }
    }
    
  2. Create a UI test extension package for your control by creating a class library project. Add references to Accessibility, Microsoft.VisualStudio.TestTools.UITesting, Microsoft.VisualStudio.TestTools.UITest.Common, and Microsoft.VisualStudio.TestTools.Extension. Change the Embed Interop Types for Accessibility to False.

  3. Add a property provider class that's derived from UITestPropertyProvider:

    using System;
    using System.Collections.Generic;
    using Accessibility;
    using Microsoft.VisualStudio.TestTools.UITesting;
    using Microsoft.VisualStudio.TestTools.UITest.Extension;
    using Microsoft.VisualStudio.TestTools.UITesting.WinControls;
    using Microsoft.VisualStudio.TestTools.UITest.Common;
    
    namespace ChartControlExtensionPackage
    {
        public class ChartControlPropertyProvider : UITestPropertyProvider
        {
        }
    }
    
  4. Implement the property provider by placing property names and property descriptors in a Dictionary<TKey,TValue>.

  5. Override Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.GetControlSupportLevel to indicate that your assembly provides control-specific support for your control and its children.

  6. Override the remaining abstract methods of Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider

  7. Add an extension package class that's derived from UITestExtensionPackage.

  8. Define the UITestExtensionPackage attribute for the assembly.

  9. In the extension package class, override Microsoft.VisualStudio.TestTools.UITest.Extension.UITestExtensionPackage.GetService to return the property provider class when a property provider is requested.

  10. Override the remaining abstract methods and properties of UITestExtensionPackage.

  11. Build your binaries and copy them to %ProgramFiles%\Common\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

Note

This extension package is applied to any control that is of type "Text". If you're testing multiple controls of the same type, test them separately so you can manage which extension packages are deployed when you record the tests.

Support code generation by implementing a class to access custom properties

When the coded UI test builder generates code from a session recording, it uses the UITestControl class to access your controls.

If you've implemented a property provider to provide access to your control's custom properties, you can add a specialized class that is used to access those properties. Adding a specialized class simplifies the generated code.

To add a specialized class to access your control

Diagram of classes in ChartControl and ChartControlExtension with the CurveLegend class highlighted under ChartControlExtensionPackage.

  1. Implement a class that's derived from WinControl and add the control's type to the search properties collection in the constructor.

  2. Implement your control's custom properties as properties of the class.

  3. Override your property provider's Microsoft.VisualStudio.TestTools.UITesting.UITestPropertyProvider.GetSpecializedClass method to return the type of the new class for the curve legend child controls.

  4. Override your property provider's GetPropertyNamesClassType method to return the type of the new class' PropertyNames method.

Support intent-aware actions by implementing an action filter

When Visual Studio records a test, it captures each mouse and keyboard event. However, in some cases, the intent of the action can be lost in the series of mouse and keyboard events. For example, if your control supports autocomplete, the same set of mouse and keyboard events may result in a different value when the test is played back in a different environment. You can add an action filter plug-in that replaces the series of keyboard and mouse events with a single action. This way, you can replace the series of mouse and keyboard events that select a value with a single action that sets the value. Doing that protects coded UI tests from the differences in autocomplete from one environment to another.

To support intent-aware actions

Diagram of the ChartControl and ChartControlExtensionPackage classes with the ChartControlActionFilter class highlighted under ChartControlExtensionPackage.

  1. Implement an action filter class that's derived from UITestActionFilter, overriding the properties ApplyTimeout, Category, Enabled, FilterType, Group and Name.

  2. Override ProcessRule. The example here replaces a double-click action with a single-click action.

  3. Add the action filter to the GetService method of your extension package.

  4. Build your binaries and copy them to %ProgramFiles%\Common Files\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

Note

The action filter does not depend on the accessibility implementation or on the property provider.

Debug your property provider or action filter

Your property provider and action filter are implemented in an extension package. The test builder runs the extension package in a separate process from your application.

To debug your property provider or action filter

  1. Build the debug version of your extension package copy the .dll and .pdb files to %ProgramFiles%\Common Files\Microsoft Shared\VSTT\10.0\UITestExtensionPackages.

  2. Run your application (not in the debugger).

  3. Run the coded UI test builder.

    codedUITestBuilder.exe /standalone

  4. Attach the debugger to the codedUITestBuilder process.

  5. Set breakpoints in your code.

  6. In the coded UI test builder, create asserts to exercise your property provider, and record actions to exercise your action filters.

See also