Coded UI in SharePoint 2013 – Reuse and Customization

Introduction

In the previous post, I have shown how to set up simple Coded UI tests, which contains URL navigation, UI interactions and assertions.
This post will be focused on splitting Coded UI actions to enhance the reusability of the tests, since this is one of the best practices (http://msdn.microsoft.com/en-us/library/dd380782.aspx) in CodedUI testing of which I believe should be applied at the start of every CodedUI project.
Furthermore, I will demonstrate how to customize recorded actions to prevent unnecessary recordings.


Prerequisites

  1. An on premise SharePoint 2013 environment (I am using version 15.0.4420 RTM installed on Windows Server 2012)
  2. At least Visual Studio 2012 Ultimate (I am using Visual Studio Ultimate 2013 12.0.21005.1 REL)
  3. A SharePoint 2013 site collection based on the developer template (I created a site collection named “GamesCollection”)
  4. A secondary SharePoint 2013 site collection based on the developer template (I created a secondary site collection named “MySecondGamesCollection”)

     

Scenario

I have created a new SharePoint solution, which contains a GamesList site feature. Upon activation of this site feature, a list is added to the site.
Upon deactivation of the feature, the list is removed from the site.
Suppose that you need to test multiple sites, you could create a new recording for every site.
However, when the amount of sites grows, this will become a tedious task. Furthermore, your generated code will grow and your solution becomes unmanageable.
I have created a second site collection named “MySecondGamesCollection” to demonstrate one recording can be used for multiple environments.

Steps

  1. Identify and split recordings
  2. Customize recordings for reusability
  3. Run the recording on the new site

Identify and split recordings

From the previous post, we the following recording methods are identified:

/// <summary>
/// Ensures the games list is added and removed on feature activation and deactivation respectively.
/// </summary>
[TestMethod]
public void EnsureGamesListTest()
{
    this.UIMap.DeactivateGamesCollectionListFeature();
    this.UIMap.NavigateToGamesCollectionListURL();
    this.UIMap.Assert404();
}

 

When navigating to “this.UIMap.DeactivateGamesCollectionListFeature()” the following is shown:

/// <summary>
/// DeactivateGamesCollectionListFeature - Use 'DeactivateGamesCollectionListFeatureParams' to pass parameters into this method.
/// </summary>
public void DeactivateGamesCollectionListFeature()
{
    #region Variable Declarations
    BrowserWindow uIGamesCollectionDevHoWindow = this.UIGamesCollectionDevHoWindow;
    HtmlInputButton uIDeactivateButton = this.UIGamesCollectionDevHoWindow.UISiteFeaturesDocument.UIDeactivateButton;
    HtmlHyperlink uIDeactivatethisfeaturHyperlink = this.UIGamesCollectionDevHoWindow.UIDeactivateFeatureDocument.UIDeactivatethisfeaturHyperlink;
    #endregion

    // Go to web page 'http://sharepoint2013/sites/GamesCollection/_layouts/15/ManageFeatures.aspx'
    uIGamesCollectionDevHoWindow.NavigateToUrl(new System.Uri(this.DeactivateGamesCollectionListFeatureParams.UIGamesCollectionDevHoWindowUrl));

    // Click 'Deactivate' button
    Mouse.Click(uIDeactivateButton, new Point(29, 21));

    // Click 'Deactivate this feature' link
    Mouse.Click(uIDeactivatethisfeaturHyperlink, new Point(79, 8));
}

This code is present in the file “UIMap.Designer.cs”.
Important note: Never make changes in this file directly, since:

  1. It is generated by a tool. This means that it is likely that your changes will be discarded when recordings are added or changed.
  2. When using source control, resolving conflicting changes in UIMap.Designer.cs files directly could make the UIMap corrupt and you will not be able to record/edit any methods.

There are limitations in what recording can do and custom code might be needed to enhance the CodedUI experience.
In step 2 in this blog post I will show how it is possible to make changes to the UIMap without impacting the Designer.

Moving back to the “DeactivateGamesCollectionListFeature” method, this method does more than deactivating the feature.
It starts by browsing to the site features page, which is functionality that could be shared by other tests in the future, so splitting this step into a separate method would enhance the reusability of our tests.

This can be done by double clicking on the UIMap.uitest item in the solution explorer.

Figure 1: UIMap.uitest item

The following window appears:

Figure 2: UIMap editor

In this UIMap editor window an overview of all recordings (left) and UI controls that are used in the recordings (right) is shown.
Right click on the second action listed below the “DeactivateGamesCollectionListFeature” and click on “Split into a new method”.

Figure 3: Split into a new method

Confirm by clicking Yes.
The following two methods exist:

Figure 4: Separated methods

Rename the first method (right click -> Rename) to “NavigateToSiteFeaturesPage” and the second method to “DeactivateGamesCollectionListFeature”.
Confirm by clicking on Yes.

The “EnsureGamesListTest” method in the “GamesListTest” class needs to be changed by adding the new method.

public void EnsureGamesListTest()
{
this.UIMap.NavigateToSiteFeaturesPage();
this.UIMap.DeactivateGamesCollectionListFeature();
…

 

Customize recordings for reusability

Before running the test on the new site collection the URL based recordings need to be changed to more generic recordings so that they can navigate to both site collections.

Back in the UIMap editor, right click on “NavigateToSiteFeaturesPage” and click on “Move code to UIMap.cs”.

Figure 5: Move code to UIMap.cs

Confirm by clicking Yes and do the same for the “NavigateToGamesCollectionListURL” URL.

Open the UIMap.cs file and it can be noticed that code has been added. This code originates from the Designer file and has been copied to the UIMap.cs file.
Change the methods as displayed below and remove all other code so that only two methods are present in the UIMap.cs file.

public partial class UIMap
    {

        /// <summary>
        /// NavigateToSiteFeaturesPage - Use 'NavigateToSiteFeaturesPageParams' to pass parameters into this method.
        /// </summary>
        /// <param name="siteCollectionUri">The site collection URI.</param>
        public void NavigateToSiteFeaturesPage(Uri siteCollectionUri)
        {
            #region Variable Declarations
            BrowserWindow uIGamesCollectionDevHoWindow = this.UIGamesCollectionDevHoWindow;
            #endregion

            // Go to the site features page on the site collection as specified in the siteCollectionUri parameter
            uIGamesCollectionDevHoWindow.NavigateToUrl(new Uri(siteCollectionUri.ToString() + "/_layouts/15/ManageFeatures.aspx"));
        }

        /// <summary>
        /// NavigateToGamesCollectionListURL - Use 'NavigateToGamesCollectionListURLParams' to pass parameters into this method.
        /// </summary>
        /// <param name="siteCollectionUri">The site collection URI.</param>
        public void NavigateToGamesCollectionListURL(Uri siteCollectionUri)
        {
            #region Variable Declarations
            BrowserWindow uIGamesCollectionDevHoWindow = this.UIGamesCollectionDevHoWindow;
            #endregion

            // Go to the GamesCollection list on the site collection as specified in the siteCollectionUri parameter
            uIGamesCollectionDevHoWindow.NavigateToUrl(new Uri(siteCollectionUri.ToString() + "/Lists/GamesCollection"));
        }
    }

 

Go back to the GamesListTest class and change the calling methods.

public void EnsureGamesListTest()
        {
            this.UIMap.NavigateToSiteFeaturesPage(new Uri("http://sharepoint2013/sites/MySecondGamesCollection"));
            this.UIMap.DeactivateGamesCollectionListFeature();
            this.UIMap.NavigateToGamesCollectionListURL(new Uri("http://sharepoint2013/sites/MySecondGamesCollection"));
            this.UIMap.Assert404();
        }

 

Run the recording on the new site

Now run the test and it will navigate to the “MySecondGamesCollection” after which it will succeed.

Figure 6: Test on new site succeeds

 

Conclusion

When recording actions, minimize the number of actions for one recording and determine generic actions that could be used for multiple tests. Create separate recordings for these actions.
The purpose of generic actions is that they will be called by various tests and it is important that these actions are as generic as possible. Investigate how these actions can be customized and move them to the UIMap.cs file for further customization.
As your CodedUI project grows, I believe this approach will enhance the maintainability of your project and reduce repetitive recordings.

Leave a Reply