2020 / JANUARY / 27


Automation TestingUnit Tests

Best Practices for UI Automation Testing


Best Practices for UI Automation Testing

It is true that UI automation tests are hard, a road that can teach you a lot of things but let me tell you in any testing practice you follow it is completely in your hands to make the task easier like a high-speed car. I have seen many testing engineers think of UI Automation Tests as an Unstable and Unreliable testing strategy but let me tell you it is just because of bad practices that test engineers follow, which makes UI Automation Tests unstable and unreliable.

It is very hard to say what are the rules you should follow to design a stable and reliable automation framework, as every rule has an exception associated with it. Still, I have tried to aggregate a list of the 20 best practices you should follow:

1. Don't Rely only on Automation Tool: One of the main and important practices that you need to follow straight away is not to rely only on UI Automation. You must understand this fact that high-level tests are only shielding mechanisms to detect bugs that were not discovered on the first 2 levels.

Manual_and_Exploratory_Testing_Triangle
Mike Cohn, one of the most famous Agile and Scrum instructors, has given us a beautiful representation of the agile test pyramid. According to the diagram, if we go as per the Automation "ice Cream Cone" Anti-Pattern, major emphasis is laid down on Automation on UI, as most developers believe that test automation has many benefits like lower cost, speed up testing, increased coverage but many never get past the initial investment that is required to get everything working.

Mike Cohn inverted the ice cream cone and introduced the ideal Test Automation Pyramid that improves the ROI of automation.

Base Layer: Unit Tests: As you can see clearly, in the pyramid more emphasis is on Unit testing i.e. testing is done in the development stage. This means running unit tests after every build. These tests are fast, cheap and easy to conduct. Running more of these tests allows us to check our work and get feedback. Quick feedback results in early discovery and removal of the bugs.

Middle Layer: Acceptance/ Integration/ Component Tests: After unit testing comes the next phase Integration Testing where logic and business process are tested. Integration testing is done to ensure that all components work together properly. There are 2 options for you: You can either automate in this phase or automate the UI Tests. Automating at this phase has many benefits:

  1. Few problems
  2. Easy maintenance
  3. Fast execution. Automated are slower than Unit tests but still faster than UI tests.

Top Layer: UI Tests: Try to run these tests less frequently, as these tests are costly and difficult to prepare. It is advisable that you should automate only the most critical tests.

2. Good Manual Test Case is as important as Good Automation: It is advisable to write manual test cases first by identifying the prerequisites with the objective of writing test cases that are less dependent on other test cases. Automation engineers should run these test cases at least once. Experts say that more errors are discovered in the actual execution phase than the test automation development phase.

3. Understand the application first, before Testing: It is important to understand the application and its dependency before testing an application. Tool selection depends on the technologies being used in the software. If it is a web application, it is important to know the supported browser and if it is a desktop application know the language that is being used.

4. Create a portable Test automation framework: Portability of the test automation framework is also a very important task. It would be a very tricky task to run an automation framework on a machine other than the machine on which it was designed. This is a very bad practice as it requires a huge effort on the part of other team members to run an automation framework on a new machine, where they have to struggle with the setup task. You can follow these tips to avoid such issues

  • Do not store test automation files required for test execution on the local machine. If test automation files are small you can attach them to the testing framework by storing them in a control version under the testing framework. If they are large you can upload them to cloud storage. The only thing left will be to implement a mechanism that will download the files to the right location during the first test execution in case they are not present there.
  • The same case goes for the webdriver also. There is an excellent tool WebDriverManager. This tool handles all your worries, all you need to do is to configure additional java dependency in your framework, and all the web drivers will be downloaded and configured automatically.

5. Name tests wisely: Test names should be very clear and provide a description of what tests exactly aims at. Following are the reasons for why should we name a test smartly:

  • Even after a year, you should be able to verify what test was done.

  • Clear naming if rests helps in a better understanding for the team members.

  • In the case of test failure, you should be able to determine which functionality was broken just by looking at the name.

  • You can use "_" instead of CamelCase to separate words in the test case name.

    Example-
    Bad test name-
    @Test
    public void countbookedtickets() {......

    Good test name
    @Test
    public void count_booked_tickets_for_3pm_show_1oct2019() {.......

6. Don't run tests across all target browsers: Running all tests across all target browsers is not a wise option. We need to test Browser compatibility, which can be done using a limited test suite also. Let's take an example, Suppose I want to check the Gmail Login functionality across 3 target browsers Google Chrome, Firefox and Internet Explorer. We want to check the functionality of 50 accounts. One simple testing approach would be to test all the 50 accounts login on all the 3 browsers. Other, more sensible approach would be to test all 50 on 1 browser and 1 each account on the remaining 2 browsers. We can test the basic login functionality whether it is working or not with one user credential only. There is no need to do the redundant tasks of doing the same thing with all credentials. If one credential is working fine and all 49 are working fine in another browser then 49 test cases will work fine in this target browser also.

7. Hire a Dedicated Automation Engineer: Test automation is itself a full-time job. It is not possible for Manual testers to do both tasks. So it is recommended to create an Automation team where one person can be an Automation engineer like a team leader and other members should be employed only for test automation.

8. Select automation tool as per your resources: Language learning is a time taking process. It will unnecessarily increase the development time. It is always advisable to buy an automation tool that can minimize this learning curve. For example, if you have developed the project in Java and you are familiar with Java, C++ but C# is a completely new language for you, in that case, there is no point in selecting a tool that does not offer any of the familiar languages to write scripts.

9. Better to avoid UI Automation when not mandatory or when alternatives are present: UI Automation tests are always tougher than other automation tests. So, if there is a situation where UI automation can be avoided when better alternatives like command line are present then it's better to skip UI Automation. For example, if we want to check whether the software is installed or not. One thing we can do is automate the GUI of software installation, which will start the installation and will press the next button multiple numbers of times.

10. Test Builder Implementation: Test Builder aids in creating a separate class that contains all data like for an online shopping product size, manufacturing date, price, etc. that need to be created and managed during tests. A class that we create can be reused in the future.

11. Efficient UI Mapping: One of the best practice that is considered is UI Mapping. The mapping user interface is a very efficient way to handle the user interface but also to create and perform automated tests. All the information is stored in one place, if any changes occur in the front end, CSS or HTML all you need to do is to reflect the change in a single file. There are a variety of ways to perform UI Mapping:

  1. Use the property file with Key-Value pairs.
  2. Create a class or a structure to store the element's name along with its id.

12. Create your own set of Methods: Creating your own set of methods have any advantages like it helps to speed up the code or we can create code pieces that are reusable and repeatable. For example, if we are talking about a click functionality where the code for a click will remain the same only the element id will change, in this case, if we say click on the login button and wait for the login page to load. Here the click and wait functionality can be grouped together to create one single reusable entity.

13. An automation tool is important but they are not the solution to everything: UI Automation is not an easy task. Some testers think selecting the right tool is the only worry. But the truth is right tool selection is just the beginning. You need good resources that mean a good team to complete the automation process. Hiring good resources is equally important. Often automation tools are buggy, that can get stuck around in identifying complex objects in the application. If the resources are good they can definitely work around and find a solution but if they are not good then they will get stuck and everything will come to a halt.

14. Use Data-driven testing: Data-Driven Testing is simply parameterized test cases. They are important and helpful when will need to test the same workflow but by using different data. Suppose we want to search for marks of 4 students. The tests would look like this without using Data-Driven approach:

@Test

public void findMarksJohnForEnglish(){

  homePage.open();

  homePage.waitUntilPageLoaded();

  homePage.findMarks(John, English);

  Assert.assertTrue(marksPage.getMarks().size()\>0);

}

@Test

public void findMarksAlbertForEnglish(){

  homePage.open();

  homePage.waitUntilPageLoaded();

  homePage.findMarks(Albert, English);

  Assert.assertTrue(marksPage.getMarks().size()\>0);

}

@Test

public void findMarksMarcForEnglish(){

  homePage.open();

  homePage.waitUntilPageLoaded();

  homePage.findMarks(Marc, English);

  Assert.assertTrue(marksPage.getMarks().size()\>0);

}

@Test

public void findMarksKenForEnglish(){

  homePage.open();

  homePage.waitUntilPageLoaded();

  homePage.findMarks(Ken, English);

  Assert.assertTrue(marksPage.getMarks().size()\>0);

}

What will happen, when you need to find marks for 100 students? Our test will grow fast and at the same time will become unhandy and unmaintainable. Even in the case of a small change, you need to go through all the tests and apply the change to all the tests.

In such a case we have the best option, Data-Driven Testing. Let's have a look at the above example but from the view of Data-Driven Testing.

@TestData

public static collection\<Object[]\>testdata(){

  return Arrays.asList(new Object[][]{

    {John, English},

    {Albert, English},

    {Marc, English},

    {Ken, English}

   });

}

public  DataDrivenExampleTestCase(Marks marksFrort, Marks marksIn){

  this.marksFor=marksFor;

  this.marksIn=marksIn;

}

@Test

Public void verifymarksforDifferenStudents(){

  homePage.open()

  homePage.waituntilPageLoaded();

  homePage.findMarks(marksFor, marksIn),

  Assert.assertTrue(marksPage.getMarks().size()\>0);

}

Looks clean and clear right? All we have done is used collections and when there is a change in the test data we just need to edit collection, other logic remains the same.

15. Setup information before @Before annotation: Any kind of setup information like the type of browser, URL to be opened and so on should be specified before @Before method or any such method. This declaration will help the framework being used to know that these actions need to be performed before executing any automated tests.

16. Avoid adding more comments: Tests should be clear and simple to read. It is advisable to avoid the comments in the code. If you want to explain what is happening in a line by leaving a comment. Then, you are probably doing something wrong. Suppose I want to show in my code that the code will wait for n number of seconds before the index page loads. If I am only writing a piece of line in code like-

withTimeoutOf(20,TimeUnit.SECONDS)

This piece of code will definitely work but it is not clear in terms of description. You can create a method and place this code inside the method. Method name should be clear enough to explain to the reader that it is a method indicating to wait for n number of seconds before index page loads.

indexpage.waitUntilIndexPageLoaded();

17. Always follow test design patterns and principles: A design pattern is a specific solution for a specific problem. On the other hand, design principles are complementary in nature where design pattern aims at specific problems, design principles apply regardless of context. Design principles will basically give you guidelines or rules to follow to design a well built and maintainable software.

You must be wondering how it is related to UI Test Automation? How it is going to solve the complexities faced in UI Test Automation?

UI Test Automation is not a new field. There were so many pioneers, apart from them each and every organization or a professional from Software Testing is trying this UI Test Automation. With so many people involved there is every type of experience and every type of suggestion available to counter these complexities.

Design Patterns and Design Principles act as powerful navigators. Design Principles tell you how to proceed safely in general and the Design Pattern gives you clear instructions on how to handle a specific problem.

18. Consider using a BDD framework: BDD can be applied for any type of testing like Unit, Integration, component testing but UI Testing is one of the main areas where BDD can be applied with great success. BDD is a software development methodology where software is described and implemented in terms of behavior.

There are several reasons for the success of BDD in UI Automation:

  • BDD helps to avoid code duplication, where separate building blocks which are called steps are described. Thus, it forces you to follow a strict code organization.
  • BDD uses Gherkin to write test cases simple language which helps the Business side i.e. Test and Project Managers to understand these tests. Thus, they can make recommendations beneficial from a business point of view.
  • BDD helps to create specification in easy to understand language that can help the team to understand tests and requirements more clearly. Thus, creating a strong understanding and promoting team collaboration. It means that BDD helps to create clear test documentation. It will not waste your time and other team members time as you don't need to explain the requirements to other team members.

Let's go through an example to have a clear understanding of the concept:

Suppose I have written tests like the one below:

HomePage homePage=new HomePage();

homePage.open();

homePage.waitUntilPageLoaded();

Assert.assertEquals(homePage.getTitle(), "Welcome to FrugalTesting Blog"):

ArticlesPage articlePage=homePage.findArticle("Load Testing");

List<String> foundArticles=articlePage.getArticles();

Assert.assertTrue(foundArticles.size()>0);

The example above is easy, right? We aim at finding the list of articles with keyword Load Testing on the site FrugalTesting Blog. But if you are a Manager how easy do you think It will be for you to read and understand this code without any assistance? You may be happier to see tests written in a form like below:

Given that John opened the home page

Then he should be able to see the home page with the "Welcome to

FrugalTesting Blog" Title

When he searches for the articles with keyword Load Testing

Then he should be able to find some articles

This is the example of writing tests in Gherkin Language.

19. Take screenshots and Logs from the HTML Sources for failure investigation: It is a very good practice while implementing a UI Test Automation framework you also implement a mechanism that will take a browser screenshot in case of a test failure. You must be thinking why do we need this feature? Let me explain to you. If you take a screenshot, you will be able to save the state of the web application during each step. Thus, it will help you a lot during debugging. My personal experience tells that Serenity Framework is a very wonderful framework that has an inbuilt mechanism for the screenshot. So, you don't need to care about the implementation. Every step will also show the screenshot also.

20. Wait: Don't use Thread.sleep(): There is a thumb rule that never ever use Thread.sleep() unless there are specific test requirements. Thread.sleep() blocks the test thread for an exact number of seconds. It gives you the ability to pause the test execution. Have you ever wondered why we need such a pause facility? Does it have any benefits?

There are cases where we need to use Thread.sleep() in order to pause the test execution. The behavior of a web application depends on many factors like network speed, current load on application servers and many more. Due to all these factors, it becomes difficult to predict the exact time a specific page or a web element will take to load. Here, Thread.sleep() comes handy. It will help to pause the test execution and help you to monitor the parameters.

So, we are done with all the Top 20 UI Test Automation Best Practices You Should Follow. Please note, there are no hard and fast rules, these are simply the practices that we recommend. It is advised to follow these practices and let us know the change that you can see.

Happy Reading!!!

Share:


Recommended Posts