Best Practices of choosing good locators for your test automation scripts

21 / May / 2015 by Vishal Kumar Tyagi 3 comments

One of the important requirements of a successful test automation project is the robustness of your code. If the properties of GUI or GUI itself of the application under test changes and your automation code are sensitive to GUI changes, you’ll lose valuable time fixing the code. Good element locators greatly contribute to the maintainability of your automation project. But what is a ‘good’ element locator?

A good element locator:
• is as small as possible to indicate the GUI element
• will continue working when GUI elements around the GUI element change
• will continue working when properties of the GUI element change

Let’s have a look at these statements and show some examples.

A locator should be as small as possible
In a perfect world, each web element has an html id. Finding an element by html id is the most precise way to define an element, since the id is usually the property that’s less likely to change.

For the following html code:

[java]<div id="notifications" role="button">

</div>[/java]

This could be the element locator in Selenium Webdriver:
By.id(“notifications”)
By.xpath(“//div[@id=’notifications’]”)
By.xpath(“//*[@id=’notifications’]”)

Sometimes elements have an html id which is partially fixed. The html contains both a fixed and variable part, for instance the timestamp of the build. In the following example, we search for the fixed part of the html id by using the xpath contains function.

For the following code:

[java]<div id="notifications-20140337152741" role="button">

</div>[/java]


This could be the element locator in Selenium Webdriver:
By.xpath(“//div[contains(@id, ‘notifications’)]”)

A locator should not get effected by changes to its parents
If the element has no html id, we must find other ways to locate the element. You might be tempted to try the ‘copy Xpath’ action in the developer tools of your browser. This is only a good idea if the source contains html id’s, if not, you might get something like:
/html/body/div/div/div/div/div/div[2]/div/div/div/div/div[2]/div/span

It’s obvious that this is a bad element locator. If 1 element is added to or removed from this html tree the element locator stops working, or worse, returns a different element.

In order to avoid specifying the complete html tree, you should look for anchor points as close as possible to your element.

Let’s have a look at the following html code:

[java]<div class="menu-item menu-item-active">

<div class="contents">

<div role="button">Home</div>

</div>

<div class="menu-item menu-item-inactive">

<div class="contents">

<div role="button">Contact</div>

</div>

</div>

</div>[/java]


Imagine that you need to find the div having the ‘button’ role in the active menu item. We cannot search directly for the div with the button role, since 2 such divs exist. Instead we need to first find the active menu item and then descend to the div with the button role.

Both are valid element locator implementations in Selenium Webdriver:
By.xpath(“//div[contains(@class, ‘menu-item-active’)]/div/div”)
By.xpath(“//div[contains(@class, ‘menu-item-active’)]//div[@role=’button’]”)

A locator should survive changes to its own properties
If an element has several properties, there’s no need to check for all properties. Similarly, if a property (or for instance an attribute in html) has multiple values, you don’t need to check for all properties.

Let’s have a look at the following code:

[java]<div class="menu-item menu-item-active accordeon">

<div class="contents">

<div role="button">Home</div>

</div>

</div>[/java]


If you need to get the active menu item, you need to search for the “menu-item-active” value of the class attribute. There’s no need to check for the “menu-item” and “accordeon” values in this attribute. Moreover, checking for these additional attributes would make the code brittle. If one of these irrelevant properties changes, the element locator will stop working.

So instead of using this element locator:
By.xpath(“//div/[@class=’menu-item menu-item-active accordeon’]”)

You better use the xpath contains function and check only for the relevant attribute value:
By.xpath(“//div/[contains(@class, ‘menu-item-active’)]”)

FOUND THIS USEFUL? SHARE IT

comments (3)

Leave a Reply

Your email address will not be published. Required fields are marked *