Thursday 19 June 2014

Object Repository Framework in CodedUI for Web applications- Type 2

After working on the Object repository framework in Codedui, there are few more modifications done for the same, which would be bit more simple than earlier.

we follow the same steps till 3rd step as mentioned in the Object repository framework in Codedui, and the generic functions which are defined in the earlier one would vary.

Step 4:

Instead of going with different functions as mentioned in the before framework, we can go with a single function which can do every action we needed. However i thought of having 3functions which would be helpful

Functions in earlier framework


SetText(string ObjectName,string Value) - this function gets the object by the properites mentioned in csv file with the unique objectname and assignes the value in the TextBox

SelectListItem(string objectName,string value) - this function gets the object by the properties mentioned in csv file and slects the value in listbox

ClickButton(string ObjectName) -  this function gets the object with objectname from csv file and clicks it

Updated Functions in this Framework

Object(string ObjectName) - this function returns the object by the properties mentioned in the CSV file

SetObject(string ObjectName, string value) - this function calls the Object function and for that particular object, depending upon the control type, the value is used.
  • if control is an edit, then it enters the value in editbox
  • if control is an Combobox, then it select the value item provided
  • if control is an checkbox, if value is true - it checks, if false - it unchecks
  • if control is an button, if value is true - it clicks the button
  • ........
GetObject(string ObjectName, string PropertyName) - this function returns the value of the property you provide in the PropertyName which can be used for any verifications/assertions

These functions are to be written in the UIMap file


 public static HtmlControl Object(string HtmlObjectName)

        {

            string objParentName = DataDictionary.excelread.dataKey[HtmlObjectName]["Parent"];

            HtmlControl objParentObj = GetParentOf(objParentName);

            HtmlControl obj;

            obj = new HtmlControl(objParentObj);

            string[] oPropNames = DataDictionary.excelread.dataKey[HtmlObjectName]["Name"].Split('|');

            string[] oPropTypes = DataDictionary.excelread.dataKey[HtmlObjectName]["Value"].Split('|');
            Assert.AreEqual(oPropNames.Length, oPropTypes.Length);
            for (int i = 0; i < oPropNames.Length; i++)
            {
                obj.SearchProperties[oPropNames[i]] = oPropTypes[i];
            }
            obj.FindMatchingControls();
            return obj;
        }



public static void SetObject(string HtmlObjName, string value)
        {
            UITestControlCollection collection;
            collection = Object(HtmlObjName);
            string cntrltype = collection[0].GetProperty("ControlType").ToString();
            switch (cntrltype)
            {
                case "Edit":
                    collection[0].SetProperty("Text", value);
                    //  myEdit.Text = value;
                    break;
                case "ComboBox":
                    collection[0].SetProperty("SelectedItem", value);
                    break;
                case "CheckBox":
                    bool value1 = bool.Parse(value);
                    collection[0].SetProperty("Checked", value1);
                    break;
                case "Button":
                    bool value2 = bool.Parse(value);
                    if (value2)
                        Mouse.Click(collection[0]);
                    break;
                default:
                    break;
            }
        }



public static string GetObject(string HtmlObjName, string PropertyName)
        {
            UITestControlCollection collection;
            collection = Object(HtmlObjName);
            return collection[0];
        }


You can even look at my other framework -
object-repository-framework-in-codedui - Type 1


Please let me know if any modifications or any changes which would help it more better.

Tuesday 17 June 2014

Object Repository Framework in CodedUI for Web applications- Type 1


Earlier when i used to work with QTP tool, the objects are well organised in the object repository and it was very easy for the maintenance or to update any properties of objects.

Where as in CUIT we face an issue with maintaining an object repository. Once we record any test case and check for UIMap.Designer.cs file we see all the controls added and its a mess to understand what exactly is happening.

After a little RnD, i have come with a object repository kind of framework for my project which i am working on. Thought of sharing so it would be helping even other.

Figure1
As seen in the Figure1, there are two additional files which have been added i.e. DataDic.cs and ObjectRepository.csv.

Below are the steps to start with building a framework.
Step1:
Adding the Parent Controls to UIMap.

Figure2
As per the Figure2, UIGoogleDocument will be the parent map. Accordingly add all the parent controls in all the pages of you application. How to add a control without recording an action can be done as per the below link Adding-ui-control-to-uimap-without recording

Step2:

Add an .csv file to the solution, i.e. ObjectRepository.csv file as showing in the Figure1.

Let the data be added in the csv file as shown below.(Note - don't have spaces. those spaces after comma are just for better understanding)

ObjectName,         ObjectType,        ParentObject,   Property,        Value
UserName,            HtmlEdit,             LoginDoc,        Name,             tbUserID
Password,              HtmlEdit,             LoginDoc,        Name,            tbPassword
ForgotPassword,    HtmlHyperLink,   LoginDoc,       Name|Id,        cbURL|cbURL
Login,                     HtmlInputButton, LoginDoc,       Name|Type,    LoginButton|submit


ObjectName is the unique name given for the each object. Parent Object is under which parent the object come. Property is what properties to be defined and value is the corresponding value for name provided

Step3:

Add an DataDic.cs file, in which we define the DataDictionary and add the values in the DataDictionary by reading the values from excel sheet.

using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.OleDb;
using System.Data;
using System.IO;

namespace DataDictionary
{
    public class excelread
    {
        public static Dictionary<string, Dictionary<string, string>> dataKey = new Dictionary<string, Dictionary<string, string>>();
        public void Readcsv()
        {
            dataKey.Clear();
            string fullPathToExcel = @"C:\Users\Administrator\Documents\Visual Studio 2012\Projects\CodedUITestProject1\CodedUITestProject1\ObjectRepository.csv";
            StreamReader reader = new StreamReader(File.OpenRead(fullPathToExcel));
            while (!reader.EndOfStream)
            {
                string line = reader.ReadLine().ToString();
                string[] values = line.Split(',');
                string key = values[0].ToString();
                Dictionary<string, string> datavalues = new Dictionary<string, string>();
                dataKey.Add(key, datavalues);
                SetDataDic(key,values[2].ToString(),values[3].ToString(),values[4].ToString());
            }
        }
        public void SetDataDic(string DicKey, string value1, string value2, string value3)
        {
            dataKey[DicKey].Add("Parent",value1);
            dataKey[DicKey].Add("Name", value2);
            dataKey[DicKey].Add("Value", value3);
        }
    }
}


Step4:

For my project what i have done is defined the functions which are used commonly. for example

SetText(string ObjectName,string Value) - this function gets the object by the properites mentioned in csv file with the unique objectname and assignes the value in the TextBox

SelectListItem(string objectName,string value) - this function gets the object by the properties mentioned in csv file and slects the value in listbox

ClickButton(string ObjectName) -  this function gets the object with objectname from csv file and clicks it

Note - All these functions are defined in the UIMap.cs file


public static void SetText(string HtmlEditObjectName, string TextToEnter)
        {
            string objParentName = DataDictionary.excelread.dataKey[HtmlEditObjectName]["Parent"];
            HtmlControl objParentObj = GetParentOf(objParentName);
            HtmlEdit obj;
            obj = new HtmlEdit(objParentObj);
            string[] oPropNames = DataDictionary.excelread.dataKey[HtmlEditObjectName]["Name"].Split('|');
            string[] oPropTypes = DataDictionary.excelread.dataKey[HtmlEditObjectName]["Value"].Split('|');
            for (int i = 0; i < oPropNames.Length; i++)
            {
                obj.SearchProperties[oPropNames[i]] = oPropTypes[i];
            }
            obj.FindMatchingControls();
            obj.Text = TextToEnter;
        }
        
        public static void SelectListItem(string HtmlComboBoxName, string ListvalueToSelect)
        {
            string objParentName = DataDictionary.excelread.dataKey[HtmlComboBoxName]["Parent"];
            HtmlControl objParentObj = GetParentOf(objParentName);
            HtmlComboBox obj;
            obj = new HtmlComboBox(objParentObj);
            string[] oPropNames = DataDictionary.excelread.dataKey[HtmlComboBoxName]["Name"].Split('|');
            string[] oPropTypes = DataDictionary.excelread.dataKey[HtmlComboBoxName]["Value"].Split('|');
            for (int i = 0; i < oPropNames.Length; i++)
            {
                obj.SearchProperties[oPropNames[i]] = oPropTypes[i];
            }
            obj.FindMatchingControls();
            obj.SelectedItem = ListvalueToSelect;
        }

         public static void ClickButton(string HtmlInputButtonName)
        {
            string objParentName = DataDictionary.excelread.dataKey[HtmlInputButtonName]["Parent"];
            HtmlControl objParentObj = GetParentOf(objParentName);
            HtmlInputButton obj;
            obj = new HtmlInputButton(objParentObj);
            string[] oPropNames = DataDictionary.excelread.dataKey[HtmlInputButtonName]["Name"].Split('|');
            string[] oPropTypes = DataDictionary.excelread.dataKey[HtmlInputButtonName]["Value"].Split('|');
            for (int i = 0; i < oPropNames.Length; i++)
            {
                obj.SearchProperties[oPropNames[i]] = oPropTypes[i];
            }
            obj.SearchProperties[HtmlInputButton.PropertyNames.Id] = null;
            obj.SearchProperties[HtmlInputButton.PropertyNames.Type] = "submit";
            obj.FindMatchingControls();
            Mouse.Click(obj);
        }

// parent added according to Figure2
        public static HtmlControl GetParentOf(string name)
        {
            switch (name)
            {
                case "LoginDoc":
                    CodedUITestProject1.UIGoogleWindowInternetWindow tmp = new UIGoogleWindowInternetWindow ();
                    return tmp.UIGoogleDocument;
                default:
                    return null;
            }
        }


Step 5:

In the CodedUItest1.cs call these functions accordingly to the test scenario as below

[TestMethod]

        public void CodedUITestMethod1()
        {
            UIMap.login();
            UIMap.ReadCSV();
            UIMap.SetText("UserName", "test");
            UIMap.SetText("Password", "password");
            UIMap.ClickButton("Login");
       }

You are done :)

You can even look at my other framework
object-repository-framework-in-codedui - Type 2


Please feel free if you got any better ideas or else if you feel any modifications could help in making this better.

Tuesday 3 June 2014

Control not found while spying with CUIT builder


This can be achieved by simply increasing the levels of object identification while recording

Suppose if there are more layers than 2, for example, in a WPF application, then it is possible to add more layers in the recordings. 

You will notice in the UIMap Designer tab (double click UIMap.uitest in the Solutions Explorer tab), that the depth of the controls, on the right side, is limited to layer that you are not trying to capture. If you try to Assert on "invisible" controls, there is a error message that the bottom of the Assert dialog "control not found". And after right clicking the Control on the "ui control map"..."Find Control"....it will never be found....again the layers of your project are not being seen by the recorder. Then change the setting the capture the appropriate layers of your project. Too many layers, too much memory. 

To fix, you will have to change the default settings in the core of your VS IDE. 

On your local PC, go to "..\\Microsoft Visual Studio 12.0\Common7\IDE". (for VS2013) Inside there is a file named "CodedUITestBuilder.exe.config". Open it in a text editor. Increase the value for the key of MaxLevelsForItemContainer to you project requirements. 

Example below: 

<!-- Use this to set the maximum level of search hierarchy for WPF and Windows Runtime Xaml controls having nested Item containers, 
when authoring or recording Coded UI tests. --> 
<add key="MaxLevelsForItemContainer" value="2"/> 

Happy coding :)

Monday 2 June 2014

Writing CodedUI code without recording and playback

Main uses of writing code without recording and playback is we can define our own custom names for the objects, same as we used to do in QTP. Which would be easy for us for updating or maintenance of the code later.

I used to record and run the code. The problem was because of the names generated by the tool, its bit hard for me to know what window is what and which object it is actually referring it. After a thorough process, here is my analysis.

Let us do this for clicking Equal button on the Calculator.
  •          The first step here is same like in QTP, which is spying the object and knowing its hierarchy.

Figure1:

In the left hand side box, we see the hierarchy for the Equal button. So for an Equal button to be defined, the Calculator window and Item window are to be defined.

  •         Now in the UIMap.cs let us define the Calculator window.

To know the properties of the UICalculatorWindow, simply select the control and the properties are defined as shown below

Figure2:


Public partial class UIMap
{
public CalcWindow CalcWindow
        {
            get
            {
                if ((mCalcWindow==null))
                {
                    this.mCalcWindow = new CalcWindow();
                }
                return this.mCalcWindow;
            }
        }
        private CalcWindow mCalcWindow;
}


·         CalcWindow is the main window. Now we need to define the CalcWindow.

public class CalcWindow : WinWindow
    {
        public CalcWindow()
        {
// defining the search properties as seen in the builder.
            this.SearchProperties[WinWindow.PropertyNames.Name] = "Calculator";
            this.SearchProperties[WinWindow.PropertyNames.ClassName] = "CalcFrame";
            this.WindowTitles.Add("Calculator");
        }
        public CalcEqualItemWindow CalcEqualItemWindow
        {
            get
            {
                if ((mCalcEqualItemWindow == null))
                {
                    mCalcEqualItemWindow = new CalcEqualItemWindow();
                }
                return mCalcEqualItemWindow;
            }
        }
        private CalcEqualItemWindow mCalcEqualItemWindow;
    }

As seen in the Figure2, the child for the Calculator window is Item window. While recognizing the object in the CodedUI, we see every button has got a window defined for it. So here we need to define EqualItemwindow for the Equal button. So this is done in the Calcwindow class as shown above.

·         The last step is defining the button.
For defining the button the its parent EqualItemWindow which is initialized in the CalcWindow class is to be defined as shown below

public class CalcEqualItemWindow : WinWindow
    {

        public CalcEqualItemWindow()
        {
// search properties for the Window
            this.SearchProperties[WinWindow.PropertyNames.ControlId] = "121";
            this.WindowTitles.Add("Calculator");
        }

        public WinButton EqualButton
        {
            get
            {
                if ((this.mEqualButton == null))
                {
     // search properites for the Button
                    this.mEqualButton = new WinButton(this);
                    this.mEqualButton.SearchProperties[WinButton.PropertyNames.Name] = "Equals";
                    this.mEqualButton.WindowTitles.Add("Calculator");
                }
                return this.mEqualButton;
            }
        }
        private WinButton mEqualButton;
    }

Finally the Equal button is defined. Now if we need to write a function to click this button, we write the following code in the UIMap class and it looks as below

public void ClickMyEqualButton()
        {
            WinButton equalButton = this.CalcWindow.CalcEqualItemWindow.EqualButton;
            Mouse.Click(equalButton);

        }



Please feel free to share if anyone has any better approaches or anything can be made better in the above approach :)