Failing to prepare is preparing to fail.
– John Wooden
Writing strong automated tests comes down to preparation. (I never thought I would be drawing connections between sports and automated tests, yet here I am.) Putting in the hard work up front pays off immensely on the back end. With a solid Page Model architecture in place, writing the actual testing scripts becomes much easier. Getting to that point can be difficult but Gregg Reed’s current sequence of posts for building an automated test suite shows how to start to build that solid foundation using a Page Model and abstraction.
The goal of this article is to outline some of the best practices associated with selecting elements on a web page. Although these examples use the Selenium Java testing framework, the principles can be applied to any automated testing framework that uses web drivers and automates user interaction with web elements.
Change is the enemy of all automated tests. Whatever application you are testing today is destined to change in the future. New releases, bug fixes, UI/UX changes… The list of reasons for change goes on and on. A solid automated test suite and Page Model architecture needs to be built to handle these changes gracefully, meaning fix the code in one spot for an update. When an update causes the same change to made in several places, the door is flung open for human error which will inevitably creep into the project. The main idea here is to minimize your Technical Debt.
The beauty of selecting elements on a web page is that there are several different ways to get the same element. But this flexibility also introduces complexity and possible bugs (usually difficult to find). There are several resources out there about all the different methods of selecting elements (the Selenium docs do a great job of showing all these ways). But it is important to remember that not all selectors are created equally. A great selector is not only unique but it is also resistant to change.
Below I have listed, in order of preference, which selectors should be used as well as some pros and cons associated with each. There are other ways of selecting elements but I generally find the best solution to locating any element to be one of these. I have also listed an example of each selector as it would be used in the FindBy tags used in a Selenium Page Model.
@FindBy(id=”addButton”) public WebElement addButton;
Pros: Using ids is the most efficient way to select elements on a web page. It is the fastest way to return a web element from the Selenium web driver. These are very resistant to development changes. Generally, depending on the developer, ids should be unique, but be careful to not always assume that they are.
Cons: Some frameworks, like SEAM MVC, auto-generate element ids. These can be very dangerous to use as selectors as they are brittle and can change in each application instance.
@FindBy(name=”username”) public WebElement usernameField;
Pros: Using the name of an element is very similar to ID. Names can be useful to differentiate various input elements on a web page.
Cons: Name is not a very common attribute added to elements by web developers.
3. CSS Selectors
@FindBy(css=”div.header a”) public WebElement navigationLink;
Pros: CSS Selectors have the most flexibility in their construction. They use the same principles as the selectors used in stylesheets which means methods like n-th child, substring matches, attribute values and several others can be used. They are also more native to browsers than xpath selectors.
Cons: These are one of the slowest selectors. They require an understanding of how the web page is organized as well as what attributes will be present on the page at a certain time. CSS selectors are easily misused and might not be unique. These selectors start to become more brittle with development changes if they rely heavily on Document Object Model (DOM) tag names.
@FindBy(xpath=”//div[@id=’results’]/table/tbody/tr/td”) public WebElement resultsField;
Pros: Xpath is the catch-all of selectors. They can be used to navigate the DOM to a specific element using tag names, attributes, ids, class names, etc. They are very similar to CSS selectors in that regard. This makes them a powerful bail-out if the other selectors can’t guarantee uniqueness.
Cons: Since they are very dependent on the DOM, they are also extremely brittle. Any change to the DOM will most likely break the selector. They are also the slowest Selenium selector and impact the overall performance of the automated tests. My recommendation would be to avoid these as much as possible. However, if it is necessary to use an xpath, locate the nearest id tag up the DOM tree to minimize the length of the expression. Each node of the DOM introduces another place for the expression to change and break the selector.
Understanding which method to use is important, but how do we actually develop the selectors that we will use? Most likely, you will spend a lot of time in your browser of choice’s web inspector sifting through the DOM. But I propose two different solutions!
First of all, work with the web developers if possible to gear applications for automated tests. When designing a web page, think about the elements that will need to be in the Page Model and come up with unique ids. Remember preparation is key! If possible, include automated testers in the development process to help design pages that will be easy to communicate with via a web driver. This will make your life so much easier when you finally sit down to start setting up the Page Model architecture.
Second of all, you can use my Selenium Selector Chrome Extension that will do all this work for you. I use it every day when I set up Page Models. It works by listening for your clicks on a web page and then determining all the possible selectors for you. It will rank the selectors, determine if it will return a unique element, and if it is the correct element. Finally, it will recommend which selector you should be using for that element based on the principles I outlined above and copy the tag to your clipboard. It is a work in progress so I would love to get feedback for improvements. The screenshot below shows the extension in action!
The takeaway from all of this is to prepare for change. Design your automated tests and Page Models to handle change easily. Design your selectors to handle change easily. Put in the work up front so that you won’t be clocking extra hours on the back end for all the changes that will inevitably happen.
I will outline some more best practices that I think every automated testing suite should have. I will show how to use asserts properly and handle errors gracefully. I will also take a look how to write strong Page Model methods that are independent of tests.