Consider a simple web application for a team transitioning to DevOps. The team wants to push new code to production at least every day, if not every few hours, and simply does not have enough time to explore it personally.
They want to use a tool to “drive” the application and make sure core functionality stays in place. To test the login process, the tool needs to find the username text field, type into it, find the password text field, type into it, and find the submit button and click it. Then it needs to find objects that appear on the next screen and make sure they are there, or not, depending on the type of test.
Then all of a sudden there is a user interface change and all the tests break. So, the team has to go in and change every test to use the slightly different connection string. That is a lot of rewriting.
The modern, under-the-hood hook to objects is often a CSS or XPATH string. For example, here’s the XPATH to a button labeled “Submit”:
And here’s how to do it in CSS:
Using these “magical strings” in tests means that when they change, testers need to do a global search and replace — except that the other submit buttons didn’t move, just the one on the login page. So, the search and replace becomes a manual process.
After making the fix, testers need to rerun the test and make sure they fixed the right things. That’s fine when you have five tests, or even when you have 500. But as Markus Clermont pointed out at Google’s Test Automation Conference over 10 years ago, once Gmail got to 5,000 tests, it was essentially unmaintainable.
The fix: Object repositories
An object repository is a collection of objects, their properties (exists, enabled, visible, innerText, tagName, class, etc.) and their tree traversal path locators, all in a structure that looks like a tree, just like the underlying code for a webpage. This allows controls with locators ranging from very specific to specific only at a component level, using wildcards like ? or * or other very general locators to reduce the possible impact from the changes to the page structure.
Visual testing extends this ability with screen capture and compare for objects. That way, if a test fails, there is a simple process to check that the test actually passed and now use the new image for future comparisons. This massively reduces the cost to update a test, making them maintainable.
Therefore, when a control transitions to a different location, a single click on the object opens the object repository and you can then adjust the locator right there, either by clicking Track to record a new one or by manually adjusting the XPath or CSS locator it was previously. Imagine we have a locator like:
“/dom[@domain='www.mydomain.com']//div[#'top-posts-2']/h4[@innertext='Top Posts & Pages']”
and that the location and inner text were both changed from being a reference to top posts to recent posts. This could become:
“/dom[@domain='www.mydomain.com’]//div[#'recent-posts-2']/h4[@innertext='Recent Posts & Pages']”
It all can be changed in line, without having to open every test to point it to a new object, thus saving you time as you automate the important things.
A good object repository will have a properties view that enables you to include, remove or update values for the properties to improve the locator in just a few keystrokes or mouse clicks. Notice in this example how the various nodes composing the locator path could also be updated at any point on the path for the needed web element:
An H4 element in the object repository with innerText equal to “Top Posts & Pages”
You may make the changes necessary, record or update the text in line, or change the properties collection that is included in the path, and then click Apply and save. Now you are ready to continue testing. Imagine the minutes you will save browsing through code on your own just to make a couple of small corrections for this one element.
The object repository goes a long way in helping automators focus on what matters. This solves most of the early issues you may encounter when creating test automation.
However, automators can still run into problems.
Issues for automators
Some components may not have strong, recognizable names — for example a radio button might be one of 10 for one radiogroup all called “radiobutton1,” “radiobutton2,” and so forth, and it may not be the only radio button group on the page, or even within the entire application under test. By using an object repository, you have the ability to change the name used in tests to something more meaningful. They may become “smbRadioBtn” and “‘entRadioBtn.” If the programmers do not provide names, an object repository can still find the object, and a tester can give that object a name.
The assumptions of what to use to match the object might involve properties that change frequently. That might make the locator fail, even though it’s still on the screen. The best-known practice is to tie the object to view properties that are unlikely to change and are likely to remain unique on the page.
Better locators will be able to find “button” with specific text, so that isn’t tied to where the button is on the page — unless that matters! Some tools observe these changes over time, along with the application, and can use machine learning to “guess” when an object has moved. We call these self-healing tools, and they have just begun to enter the market.
The object repository solves the stale and poorly named object locator problems, but it can introduce others. For example, when teams of teams are working on the same website, it is possible the teams step on each other, introducing changes in the same page that cause the tests the other team is working on to report a failure. These problems exist with or without object repositories, but you may need to have the object repository versioned right along with the code or placed in branches.
This extra layer of coordination does cause added complexity. Then again, giving names to objects and creating reuse creates simplicity. Think of the object repository, then, like a code library of sorts that holds how to connect to objects, making tests simple.
If your tests are becoming hard to maintain, you might look into tools that include an object repository. In my experience, if you don’t add a tool you’ll likely end up building your own anyway, but unless you’re careful, it will likely be awkward, be brittle and have half the functionality you’d like it to have. Save the time and effort and explore existing options for object repositories. You’ll probably be spared some headaches.