Duda’s Test Automation Project: Supporting Growth and Improvements
Today, automated testing is an integral part of the development process for large software products. The need to test products frequently led to the development of test automation. In order for automation developers to reach a high level of testing, they need to tackle these challenges in a systematic way. In this blog, I’ll outline some of the difficulties associated with test automation and explain how the automation team at Duda solved most of these problems to reach a reliable, highly productive level of automated testing.
What Is Automated Testing?
Automated testing imitates human actions such as click, hover, type text, etc. It is very similar to the manual testing done by teams in QA, but unlike the people who do QA, automated tests don’t get tired, they don’t forget anything, and they do exactly what they are told to do.
For every action that we want to perform in a browser, we need to provide two important details:
- What is the action?
- On what element do we want that action to be executed (for example, on a button, textbox, etc.)?
In order to choose the element upon which we want to perform the action, we need to provide a “pointer” to that element. In browsers, we point to the elements using the HTML element hierarchy of the page.
I won’t go too deeply into this topic, but it is important to understand that all the elements on a page, including buttons, text boxes, images and other elements, can be found in this document so we can use it to point a single element.
After we have pointed to a single element, how do we perform the desired human action (for example, clicking) in an automated way?
A number of different tools are used to perform human actions in browsers. Here at Duda, we use Selenium, a suite of tools that helps us point to the element and perform the desired actions on it automatically, and with the help of Java programming.
Instability in Automated Testing
As mentioned earlier, instability is a major challenge of automated testing. Here are some reasons why instability can occur:
- The pointers to an element are not univalent, or they change and are not constant so that in the automated test, the element cannot be found.
- The product is constantly under development for additional features, so the user interface is always changing, and the test can’t be conducted.
- Waiting for the browser software to load and switching between pages causes the test to fail.
- The automated test is written sequentially so that if the test fails at the beginning, it causes subsequent tests to fail as well.
- The tests are written in complicated code that is hard to understand and follow, instead of simple human language.
When we understand the reasons for the test instability, we can start coming up with solutions.
Here at Duda, we’ve created a design pattern for automated tests that we call WWHB: The letters stand for What Where How Browser. The basic principle of this design is that answering these questions will guide us in building the code:
What to test: These are the test classes in which we write the test cases as prose. No loops, no difficult algorithms. Only pure human actions.
Where to find the elements: These are the page object pattern classes. I will elaborate on these later in this post.
How the UI flows: These are classes I call Logics. They help the test classes to group several UI actions together for a single method. For instance, log in as a single method which encapsulates several web actions.
Browser: One of the stability issues I mentioned is the asynchronous nature of the web browser. The browser principle guides us in how to manage browser actions. I will also elaborate more on this principle later.
When writing a test, the automation engineer creates the test class which asks the logic classes to execute a web action according to the specific scenario tested.
In turn, the logic asks the proper page objects to execute this web action. Only the logic knows the correct order of page objects to call. The page object holds an instance of a pointer to a web element but it is not the one executing the action on the browser.
The page object calls a special class that we call BrowserToucher for help in executing the action.
This design solves many ambiguities and lines up the code in a proper manner so that each question in the WWHB structure gets answered.
If we examine this line of code starting from the test class all the way down to the BrowserToucher, we notice that the only actual class executing any action on the browser itself is the BrowserToucher. This structure may seem strange at first, but it helps us with the most common cause of test failures an automation engineer encounters.
Usually, Selenium code is written in a popular programming language like Java, C# or Python. Most test failures are not caused by wrong code lines. Usually, the code is simple and there is not too much room for bugs in the code itself. The main fault in Selenium tests is when the test executes an action on the browser. In that small yet significant moment, many code exceptions can be thrown due to issues such as connection timeout, latency, ajax calls and more. When using a single class through which all code must go before accessing the browser, you can perfect the browser touch method to handle every unexpected error.
In this way, instead of multi-access points to the browser (Left), access is controlled and managed by a single BrowserToucher class (Right).
The layer immediately above the BrowserToucher is the page object layer. Many automation teams implement a page object design pattern which states that the web element selectors should be contained within classes called page objects, and they hold all the data about the page they represent.
At Duda, we’ve improved the common page object structure that uses the Page Factory design. The main issue with this design is that page objects hold non-reusable code. We explicitly write every method in the page object class to click on elements or set text to text boxes. Our new design uses a different approach that contains an inner public static class.
An Example: A Coupon Content Window
Let’s examine this case:
This is a page object of the content window of a coupon. It holds many web elements, including “Title”, “CouponName” and more. It is clear that the page object has very few methods, although it has many page elements.
This is the result of using the inner public static class. It inherits all the basic methods such as click, hover, set text and more from the base class it extends, and thus we get a very lean page object. To call a web action on one of the elements, we can access them in a static form and then call on them the required web action.
The Wide-Reaching Benefits of Good Test Automation
This post introduces the basic ideas upon which the automation team at Duda has built a new and very robust test suite. Although these are the core topics, we’ve created many more mechanisms that, together, construct the Duda automation project.
We’ve decreased test development time by more than 50%, decreased debug and maintenance time by more than 90%, and shortened the length of test execution from 4 hours to 15 minutes. Test coverage has more than doubled, and the reports rarely give false positives.
The tests are robust and easy to understand and maintain. As for automation team productivity, it has greatly increased.
The benefits, however, go well beyond automation team productivity. Development bugs at Duda are found immediately after they are committed to the main branch; thanks to the increased trust Duda has in the automation suite, the whole company has changed its development process, shrinking the time between deploys and changing the way developers test new features on their branch.
Test automation helps support a rapid development process, creating a safety net on which the whole company can rely. Ultimately, this supports company-wide improvements and growth.
Good test automation is tricky and sometimes difficult to achieve, but new ideas and good code writing practices can help make it achievable.