Understanding the code generated by “Coded UI Test” – Part 2


This blog post has been updated to reflect changes in VS 2010 RC or later build.  If you are on VS 2010 Beta 2, please upgrade before trying this post. 


This is Part 2 of two part series.  In Part 1 we focused on –



Why is generated code not a straight-line code?


In this part, we will focus on –



How is generated code making reusability & customization easier?


Here we will look into –



  1. Reusability of the test code

  2. Data Driving the Test

  3. Customizing Search Properties

  4. Customizing Complete Method

  5. Complete Control over Code

Reusability of the test code –


By generating code in separate class and methods, the tool encourages reusability.  Say that in addition of the above test, I also want to test the results for Top 3 most popular search phrases. Since my test steps are pretty similar to the above, I should be able to reuse the above code.  I copy the above method and create a new test method by renaming it –

[TestMethod]
public void Top3SearchesTest()
{
this.UIMap.LaunchBing();
this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
this.UIMap.CloseBing();
}

Data Driving the Test


The next step is to data drive the above test method for the Top 3 searches. I will use Mathew’s blog here to do that. The artificial data for Top 3 searches in CSV format that I have are –






Phrase, FirstLinkText, FirstLink, MinResults
microsoft, Microsoft Corporation, http://www.microsoft.com/, 100000000
wikipedia, Wikipedia, http://www.wikipedia.org/, 1000000
hotmail, Windows Live Hotmail, http://mail.live.com/, 100000000


The code (after some basic formatting) should look like –

[DataSource(“Microsoft.VisualStudio.TestTools.DataSource.CSV”,
“|DataDirectory|\\ArtificialTop3BingSearches.csv”,
“ArtificialTop3BingSearches#csv”,
DataAccessMethod.Sequential)]
[DeploymentItem(“ArtificialTop3BingSearches.csv”)]
[TestMethod]
public void Top3SearchesTest()
{
this.UIMap.LaunchBing();
this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
this.UIMap.CloseBing();
}

At this point, I have added the data source but the columns are still are not bound to the appropriate values. The code should look like –

[DataSource(“Microsoft.VisualStudio.TestTools.DataSource.CSV”,
“|DataDirectory|\\ArtificialTop3BingSearches.csv”,
“ArtificialTop3BingSearches#csv”,
DataAccessMethod.Sequential)]
[DeploymentItem(“ArtificialTop3BingSearches.csv”)]
[TestMethod]
public void Top3SearchesTest()
{
this.UIMap.SearchBingParams.QEditText =
TestContext.DataRow[“Phrase”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkInnerText=
TestContext.DataRow[“FirstLinkText”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkHref =
TestContext.DataRow[“FirstLink”].ToString();

this.UIMap.LaunchBing();
this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
this.UIMap.CloseBing();
}

The 3 new lines here are using the Params classes and doing the data binding.  The first line is binding Phrase column to the text typed in search edit box (which has name ‘q’) and the other two lines are binding the FirstLinkText and FirstLink columns to the InnerText and HREF of the first link respectively.


So using Params, I was able to data drive easily. The bigger benefit is that I can still use SearchBing() method at some other place without data.  This further promotes reusability – if I have a method with parameters, I can data bind any number of these parameters and use recorded (hard-coded) value for the rest.


Customize Search Properties


The other common task is to configure the search properties for a control.  In the above example, the default search properties of the first hyperlink control is dependent on the search phrase and this will result in search failure. To fix this, we can customize the search property for this using following code in UIMap.cs –

public UIMap()
{
// Remove data specific properties for the first hyperlink.
// The remaining ones are still good to get the control.
HtmlHyperlink firstHyperlink =
this.BingWindowsInternetEWindow.
BingBingDocument.Results_containerPane.BingHyperlink;

firstHyperlink.SearchProperties.Remove(
HtmlProperties.Hyperlink.InnerText);
firstHyperlink.FilterProperties.Remove(
HtmlProperties.Hyperlink.AbsolutePath);
firstHyperlink.FilterProperties.Remove(
HtmlProperties.Hyperlink.Href);
firstHyperlink.FilterProperties.Remove(
HtmlProperties.Hyperlink.ControlDefinition);
}


Here the fact that UIMap is a partial class has been used.  The code is in UIMap.cs file which is not regenerated by the tool and hence it is safe to edit.  Also, since the code is there in the UIMap constructor, all instances of First Hyperlink will get this change.  If I wanted one particular instance to get it and not all, I could have made similar change inside the Top3SearchesTest method also.


Customize Complete Method


The last item pending in the above test is to also verify the total result count. The search engines do lot of caching and hence the total results count is not same across the runs.  Hence I will ensure that the total results are more than a minimum count than the exact count.  For this, I will record a VerifyExactResultCount() method & then customize it into VerifyMinimumResultCount() method.


To do this, I go to Top3SearchesTest() method and place the cursor on new line after VerifyFirstLink() call.  I right click here and then left click on “Generate Code for Coded UI Test”->”Use Coded UI Test Builder…” to launch the tool.  I insert the verification on the total results pane’s inner text. The code should look like –

[DataSource(“Microsoft.VisualStudio.TestTools.DataSource.CSV”,
“|DataDirectory|\\ArtificialTop3BingSearches.csv”,
“ArtificialTop3BingSearches#csv”,
DataAccessMethod.Sequential)]
[DeploymentItem(“ArtificialTop3BingSearches.csv”)]
[TestMethod]
public void Top3SearchesTest()
{
this.UIMap.SearchBingParams.QEditText =
TestContext.DataRow[“Phrase”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkInnerText=
TestContext.DataRow[“FirstLinkText”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkHref =
TestContext.DataRow[“FirstLink”].ToString();

this.UIMap.LaunchBing();
this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
this.UIMap.VerifyExactResultCount();
this.UIMap.CloseBing();
}


Notice the newly added line in bold in the above code. To customize, I go to the UIMap.Designer.cs and manually copy the code related to VerifyExactResultCount() method to UIMap.cs. I then rename the method to VerifyMinimumResultCount() to get the a code like below –


(Yes, the support for customizing a method is bit limited today from user experience side and we will improve upon it in future releases.)

/// <summary>
///
VerifyMinimumResultCount –
/// Use ‘VerifyExactResultCountExpectedValues’ to pass
/// parameters into this method.
/// </summary>
public void VerifyMinimumResultCount()
{
#region Variable Declarations
HtmlSpan totalResultsPane =
this.BingWindowsInternetEWindow.
BingBingDocument.TotalResultsPane;
#endregion

// Verify that ‘1-14 of 5,210,000 results’ pane’s property ‘InnerText’ equals ‘1-14 of 5,210,000 results’
Assert.AreEqual(
this.VerifyExactResultCountExpectedValues.TotalResultsPaneInnerText,
totalResultsPane.InnerText);
}


In most cases, there would be need to copy and rename VerifyExactResultCountExpectedValues class and related code too. However, here I will pass an int variable to the method because I do not want this method to ever work on a default value.


After complete customization, the method should look like –

/// <summary>
///
Verifies that the result count is > the min value passed.
/// </summary>
public void VerifyMinimumResultCount(int minResultCount)
{
HtmlSpan totalResultsPane =
this.BingWindowsInternetEWindow.
BingBingDocument.TotalResultsPane;

// Use regular expression to get the text out of the
// inner text of TotalResultsPane.
// The inner text has format like ‘1-14 of 5,210,000 results’.
int actualResultCount;
Match resultPattern = Regex.Match(totalResultsPane.InnerText,
“[0-9]+-[0-9]+ of ([0-9,]*) results”);
Assert.IsTrue(resultPattern.Success,
“Regular expression match failed”);
Assert.IsTrue(int.TryParse(resultPattern.Groups[1].Value,
NumberStyles.Number,
CultureInfo.CurrentCulture,
out actualResultCount),
“Parsing failed”);
Assert.IsTrue(actualResultCount >= minResultCount,
“Got less than expected min result”);
}


In the above method, I did not use much code from the recorded VerifyExactResultCount() method and could have written this method by hand too. Once this is done, I need to update Top3SearchesTest() method to use VerifyMinimumResultCount().


Complete Control over Code –


All the above steps show that I, as a tester, have the complete control over the test code.  There is no code hidden behind the tool and I can modify\customize any piece of the code. The final step here to customize is to fix closing of the browser even for the failed case. The two way to do that are –



  1. Wrap the code in try\finally block.

  2. Or, move LaunchBing and CloseBing into TestInitialize and TestCleanup methods respectively.

I will use #2 because all my tests have LaunchBing and CloseBing steps as initialize and cleanup steps. The final code for two methods should look like –

[TestMethod]
public void SearchBingTest()
{
this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
}

[DataSource(“Microsoft.VisualStudio.TestTools.DataSource.CSV”,
“|DataDirectory|\\ArtificialTop3BingSearches.csv”,
“ArtificialTop3BingSearches#csv”,
DataAccessMethod.Sequential)]
[DeploymentItem(“ArtificialTop3BingSearches.csv”)]
[TestMethod]
public void Top3SearchesTest()
{
this.UIMap.SearchBingParams.QEditText =
TestContext.DataRow[“Phrase”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkInnerText=
TestContext.DataRow[“FirstLinkText”].ToString();
this.UIMap.VerifyFirstLinkExpectedValues.BingHyperlinkHref =
TestContext.DataRow[“FirstLink”].ToString();

this.UIMap.SearchBing();
this.UIMap.VerifyFirstLink();
this.UIMap.VerifyMinimumResultCount(
(int)TestContext.DataRow[“MinResults”]);
}

[TestInitialize]
public void Launch()
{
this.UIMap.LaunchBing();
}

[TestCleanup]
public void Close()
{
this.UIMap.CloseBing();
}


The final code for the above walkthrough is attached as BingTestFinal.zip.

BingTestFinal.zip

Comments (18)

  1. ZhekaAlias says:

    Is there any way how to make one test work with different browsers?

    For example make this test to work with Chrome or Firefox without recording UIMap methods specially for specific browser.

  2. Zheka –

    Please refer first table in  http://blogs.msdn.com/mathew_aniyan/archive/2009/05/26/no-more-ui-regressions.aspx for platforms supported.

    Today, Coded UI Test supports IE7 and IE8.  FireFox support is in pipeline and will be available soon. For other browsers, we are looking at partners to add support using extensibility APIs.

    Once FireFox support is out, you can get the same recordingcode played on different browser by setting BrowserWindow.CurrentBrowser property.

    Thanks.

  3. Bruno Soko says:

    Hi,

    I've started using Coded UI Test for testing, as well as the customization of methods, etc, and I have a couple of questions and I need you to please answer…

    1ST – After doing the recording of an automated test, do I need to move the coded generated on the UIMap.Designer.cs to the UIMap.cs? I'm asking this 'cause my understanding of a sentence on this blog says: "Here the fact that UIMap is a partial class has been used.  The code is in UIMap.cs file which is not regenerated by the tool and hence it is safe to edit"…

    2ND –  How do I avoid Recording errors like i.e : "… Control Already Exists…" this happens when I'm recording something and then I want to generate the code.

    if you could answer this will be awesome.

    thanks so much!

    Bruno.

    (sokobruno@hotmail.com)

  4. Sorry for late reply.  For some reason, my blog settings got messed up and I had trouble login in.  In general, the Coded UI Test forum (social.msdn.microsoft.com/…/threads) is better place to post your questions as that is monitored by many folks & you will get faster response.

    1st – You need to move only if you are customizing the method.  We are planning to release an editor for directly editing the XML file and ease are customization issues but for now this is the way to go.

    2nd – Difficult to say the cause for this.  I suggest you put this on forum with repro steps.

    Thanks,

    Gautam

  5. Bhavitha says:

    Hi,

    I have a clarification in Reusability of code.

    how to create another test method in the same .cs file while Test view shows two different methods.

    But still it points to same .cs.

    I need to implement same klnd of methodology.

    I tried copying and pasting same method and then renaming it. But still there is only one testmethod in Test view.

    Can u explain this.

    Thank you

    Bhavitha.

  6. @Bhavitha – Are you rebuilding the project?  In VS 2010, we have changed the defaults and now the test methods show up in Test ViewList only after rebuilding.

  7. Bhavitha says:

    Hi,

    I did rebuild the project.

    Also when i run the test, only that test method runs and not the one which i have copied and renamed it.

    Only when i comment the recorded test method, the second testmethod which is copied and renamed runs.

    Can u help me how it is carried out.

  8. Ok, probably you are running into some bug here.  Please use blogs.msdn.com/…/forums-are-the-best-place-to-ask-questions.aspx and put your query on the forums.

    Thanks.

  9. TestInitialize says:

    Hi Gautham

    How do u use the TestInitialize/ClassInitialize if using CSV file and TestEditor

  10. I am not sure I get your question.  For comments unrelated to blog, please make a detailed post to the forum to get quicker response.  For Coded UI Test, the forum is – social.msdn.microsoft.com/…/threads

  11. Shraddha says:

    I'm trying to use Winproperties to write my coded ui test as posted in ur blogs.msdn.com/…/hand-coding-a-coded-ui-test.aspx blog, but my VS is not recognizing 'WinProperties', error: 'The name WinProperties does not exist in current context'.

    I have VS 2010 ultimate edition installed with feature pack 2.

    please help

  12. @Shraddha – You are probably missing a reference or not adding the using statement for the namespace.  Try doing CTRL+. (dot) on the error and see if you get an option for adding the using statement.

    Note that you should reference to Microsoft.VisualStudio.TestTools.UITesting.dll.

    Thanks

  13. Great Post. I have around 10 test methods in one VS solution. I want only 8 tests to have test initialize and cleanup run. Can this be acheived?

  14. No, Nitin.  You can do it differently by refactoring the code into two classes.  Have the 8 methods in one class where you define test initialize and cleanup and other two in different class where you don't.  If these two classes need to share some common code you can refactor that common code in a separate class or in a common base class.

  15. PNR says:

    Hi Gautam… Iam using Coded ui tests for automation by using the customised generic functions and using the search properties of the controls generated while recording. But the thing is all my methods and the script for the aaplication are at one place,i.e., UIMap.Designer file. Can u please let me know how to organise all the methods in a library and the scripts in other file for the easy maintanability.

    Thanks in Advance!!!!

  16. I recently read this great article on MSDN – msdn.microsoft.com/…/hh875174.aspx. See if this helps

  17. PNR says:

    Thanks Gautam…The link helped me very much and worked well… Can u share me the idea of executing the coded ui tests in HP QC? I was trying but struck up in the midst…

    Thanks in Advance!!!!!

  18. @PNR – I don't know.  Check on forums if anyone in community knows about this.