Home Guide Best Practices for Test Automation : Checklist

Best Practices for Test Automation : Checklist

Shreya Bose, Technical Content Writer at BrowserStack -

Automated testing is no longer an option, it’s a must-have in every tester’s bag of tricks. With software being rolled out faster to meet ever-increasing customer demands and competition, test automation will continue to be on the rise. Testing early and fast helps identify bugs faster, saves time, effort and costs to a large extent.

Naturally, organizations expect testers to implement practices that result in robust, maintainable, intelligent test automation. This article outlines some of those practices, acting as an automation code review checklist of sorts.

1. Focus on documentation

Automation code is usually written, added and updated by multiple individuals to a version control system. In such an environment, proper documentation, comments and consistent naming conventions are of the utmost importance. It helps organize every developers’ code and helps their peers keep track of the entire code base. If one coder leaves the team or wants to add new functionality by using existing code, they can debug, update, test and analyze results with greater results.

2. No Code Duplication

There are few practices as destructive to code as duplication. Avoiding code duplication must be the primary concern on anyone’s list of automation coding standards. To quote Agile Manifesto co-author Robert C. Martin said, “Duplication is the primary enemy of a well-designed system.”

Let’s explore this with an example. It is common for multiple test teams to use code like the following:

[TestMethod]
[Description("Validate that user is able to fill out the form successfully using valid data.")]
public void Test1()
{
Driver = GetChromeDriver();
SampleAppPage = new SampleApplicationPage(Driver);
TheTestUser = new TestUser();
TheTestUser.FirstName = "Nikolay";
TheTestUser.LastName = "BLahzah";
EmergencyContactUser = new TestUser();
EmergencyContactUser.FirstName = "Emergency First Name";
EmergencyContactUser.LastName = "Emergency Last Name";
SetGenderTypes(Gender.Female, Gender.Female);
SampleAppPage.GoTo();
SampleAppPage.FillOutEmergencyContactForm(EmergencyContactUser);
var ultimateQAHomePage = SampleAppPage.FillOutPrimaryContactFormAndSubmit(TheTestUser);
AssertPageVisible(ultimateQAHomePage);
}
[TestMethod]
[Description("Fake 2nd test.")]
public void PretendTestNumber2()
{
Driver = GetChromeDriver();
SampleAppPage = new SampleApplicationPage(Driver);
TheTestUser = new TestUser();
TheTestUser.FirstName = "Nikolay";
TheTestUser.LastName = "BLahzah";
EmergencyContactUser = new TestUser();
EmergencyContactUser.FirstName = "Emergency First Name";
EmergencyContactUser.LastName = "Emergency Last Name";
SampleAppPage.GoTo();
SampleAppPage.FillOutEmergencyContactForm(EmergencyContactUser);
var ultimateQAHomePage = SampleAppPage.FillOutPrimaryContactFormAndSubmit(TheTestUser);
AssertPageVisibleVariation2(ultimateQAHomePage);
}

The code above includes multiple instances of duplication. Now, if variable changes, such as the name of the class representing the SampleApplicationPage, or even how each of the TestUser objects is initialized, complications will arise. In this example, the tester will have to update code in two places for every change. That means twice the work and twice the possibility of making a mistake.

An easy way to resolve this is to wrap the common lines of code in a method. In the example, since these are steps for setup, one can tag the method with a [TestInitialize] attribute. Additionally, let the testing framework call the method before every [TestMethod].

Here’s the reworked code:

[TestInitialize]
public void SetupForEverySingleTestMethod()
{
Driver = GetChromeDriver();
SampleAppPage = new SampleApplicationPage(Driver);
TheTestUser = new TestUser();
TheTestUser.FirstName = "Nikolay";
TheTestUser.LastName = "BLahzah";
EmergencyContactUser = new TestUser();
EmergencyContactUser.FirstName = "Emergency First Name";
EmergencyContactUser.LastName = "Emergency Last Name";
}

Now have a look at the improved code, in which the method is called before every test is run:

[TestMethod]
[Description("Validate that user is able to fill out the form successfully using valid data.")]
public void Test1()
{
SetGenderTypes(Gender.Female, Gender.Female);
SampleAppPage.GoTo();
SampleAppPage.FillOutEmergencyContactForm(EmergencyContactUser);
var ultimateQAHomePage = SampleAppPage.FillOutPrimaryContactFormAndSubmit(TheTestUser);
AssertPageVisible(ultimateQAHomePage);
}
[TestMethod]
[Description("Fake 2nd test.")]
public void PretendTestNumber2()
{
SampleAppPage.GoTo();
SampleAppPage.FillOutEmergencyContactForm(EmergencyContactUser);
var ultimateQAHomePage = SampleAppPage.FillOutPrimaryContactFormAndSubmit(TheTestUser);
AssertPageVisibleVariation2(ultimateQAHomePage);
}

As one can see, the improved code is shorter in length and cleaner due to the absence of duplicate code.

Removing duplication is instrumental to the success of code automation. Always analyze every bit of code for signs of duplication, and do everything possible, so that the code is cleaned up from this aspect.

3. Keep It Simple

It is common for programmers to continue adding code on a class or function level without having clarity on what the class or function is supposed to do in the first place. If anyone is writing two hundred lines of code at the function level, they should be worried. At this point, code clarity and quality will inevitably be compromised. Again, if a class contains twenty methods or so, it does not serve one purpose. At this point, it needs to be fragmented into smaller classes. If necessary, classes need to be consolidated within different packages.

Keep the Single Responsibility Principle in mind when writing code. The principle states that each class, function or module must carry responsibility over only a single part of software functionality. This means that if a certain functionality has to be tested, the tester knows exactly which packages, modules, functions and classes will be impacted.

4. Code only for immediate requirements

Many developers have a habit of over-engineering. This basically refers to their attempts to protect their code from future changes that might occur.

Over-engineering makes it difficult to understand the code. It adds something to the code that isn’t necessary, and anyone studying the code won’t know why it is there and what role it plays.

Over-engineering occurs in multiple ways. For example, trying to write code that can deal with all user scenarios. Imagine a test automation engineer automating the entire page object before they need to test each of the web elements. They create a class representing an HTML page. But instead of just adding methods and properties needed for the current test, they add all locators and actions to the class.

Now, this isn’t effective because the developer can’t be sure if someone will use the entirety of that code. So, what happens is that they have created large classes without minimal usable code. Whoever interacts with the code has to study it thoroughly to find useful properties and methods. Needless to say, this becomes a huge waste of time.

To prevent this, simply write code that serves the immediate requirements. For example, if someone needs to test whether a method is returning the accurate string, create a test to verify only this action. Don’t build in code meant to test for future conditions that have not yet been defined. Do not add extra code with no tangible cause.

5. Find the right automation platform

After creating a clean code, one must run it on a robust platform that enables testing on real devices. Needless to say, since users of all software run them on actual devices (desktop and mobile), all software needs to be tested in actual devices.

Unless testers have access to an in-house device lab (which are incredibly expensive to build, maintain and update), they should use cloud-based automated testing solutions. BrowserStack, for example, offers a Cloud Selenium Grid of 2000+ real browsers and devices which enable testing on a real device cloud. It also provides a framework for automated app testing with Appium and automated website testing using Selenium, these empowering testers monitor exactly how their mobile app works in the real world.

When ideating on test automation framework design, ask:

  • Is the code being developed scalable, understandable, reusable, configurable and maintainable?

By adhering to the strategies outlined above, testers and devs can create code that makes their lives easier, and yields the best possible results.

BrowserStack Logo Run Selenium Tests on 2000+ Browsers & Devices Get Started Free