More Efficient Coded UI Tests with ClassInitialize

Image

March 1, 2023

Coded UI Tests do a great job of capturing the action recordings of the steps performed in a test case. The action recordings are used to create the automated code to test the actions. Unfortunately sometimes these steps are too literal and become excessive especially when running the tests using multiple rows of parameters (that are essentially data driven tests).

In my example, I created a test case that lists some steps that include opening the application, adding a new customer record, and closing the application. The application allows for creating multiple customer records without closing and reopening the application. Closing and reopening the application for each row in the automated test is unnecessary. Shared steps at the beginning or ending of the tests including logging in/out could be good candidates to make more efficient.

Below is the example of the test that was generated from the action recordings of the test case.

       [DataSource("Microsoft.VisualStudio.TestTools.DataSource.TestCase",
                "http://localhost:8080/tfs/defaultcollection;Tailspin Toys", "53",
                 DataAccessMethod.Sequential), TestMethod]
       public void AddCustomer_ShouldSaveAndClose()
       {
           // To generate code for this test, select "Generate Code for Coded UI Test"  
// from the shortcut menu and select one of the menu items.
           // For more information on generated code,  
// see http://go.microsoft.com/fwlink/?LinkId=179463
           this.UIMap.OpenCustomerKeeper();
           this.UIMap.OpenNewRecord();
           this.UIMap.FillParams.UIText1EditText = TestContext.DataRow["Name"].ToString();
           this.UIMap.FillParams.UIText2EditText = TestContext.DataRow["City"].ToString();
           this.UIMap.FillParams.UIText3EditText = TestContext.DataRow["Phone"].ToString();
           this.UIMap.FilloutNameCityandPhone();
           this.UIMap.SaveandClose();
           this.UIMap.VerifyCustomerSaved();
           this.UIMap.CloseApplication();

       }

As you can see it generated the OpenCustomerKeeper() and CloseApplication() methods. For each parameters row for the test case it will open and close the application. These are the two methods I only want to execute at the start of the test run and the end of the test run. Also if I had other tests that could be run without restarting the application this change would benefit those tests also.

Our options are to move these steps to the TestInitialize/TestCleanup or ClassInitialize/ClassCleanup. The TestInitialize/TestCleanup however is called before each test that also includes before each row of the data driven test. Therefore, this would be the same result and open/close the application before each row. This leaves the ClassInitialize/ClassCleanup. Unfortunately it is not quite as easy as moving the method. First these two methods need to be static so this.UIMap won’t exist. Secondly, the Playback engine is not initialized in these methods. We will need to explicitly perform the Initialize and Cleanup of the Playback engine. Lastly the ClassInitialize attribute has to be applied to a method with passes in the TestContext as a parameter.

Here is the ClassInitialize method

static private UIMap sharedTest = new UIMap();

       [ClassInitialize]
       static public void ClassInit(TestContext context)
       {
           Playback.Initialize();
           try
           {
               sharedTest.OpenCustomerKeeper();

           }
           finally
           {
               Playback.Cleanup();
           }

       }

Lastly, we will move the CloseApplication() method to the ClassCleanup method.

[ClassCleanup]
static public void ClassCleanup()
{
   Playback.Initialize();
   try
   {

       sharedTest.CloseApplication();
   }
   finally
   {
       Playback.Cleanup();
   }
}

I hope you find this useful.

Mike