<linearGradient id="sl-pl-bubble-svg-grad01" linear-gradient(90deg, #ff8c59, #ffb37f 24%, #a3bf5f 49%, #7ca63a 75%, #527f32)
Loading ...

QA essentials

Your go-to quality assurance source

How To Achieve Clean Code In Test Automation?

Clean code in test automation is a controversial subject. There are a lot of unpopular opinions online about this. Clean code on its own is causing a lot of discussions among developers. There are some general rules which developers follow. They are gathered in a book called Clean Code by Robert “Uncle Bob” Martin. It is a very comprehensive book and most of the advice in it are applicable in test automation as well. Unfortunately test automation suffers from bad coding practice because of lack of understanding of importance of clean code in tests. With influx of wide variety of test automation engineers the practice of writing clean code in test automation is sacrificed because of speed of test production. QA engineers are often lagging with their work because of which they have to cut corners to complete everything in time. Clean code has deeper meaning than just being pretty.

The benefits of clean code

When we write messy code, it is difficult even for the author to maintain it or debug it. We should always aim for easier understanding of the code. The reader should be able to understand the intent of the code just by looking at the names of the methods, classes and variables. Working in a team is also a good example why we should make our code clean. Our colleagues might not understand what we wanted to do with this piece of code.

Sometimes you don’t have a proper documentation about some feature and one way to understand how it should work is to go through the code. If the code is messy, the developers reading the code will waste more time while trying to understand how it works.

For experienced software engineers, it is not uncommon to go through pieces of code over 60% of their work day. Before they start fixing a bug they would first go through the code, either by static code analysis or by debugging. When the code is clean, they don’t have problems understanding and finding the cause of the issue. Otherwise, they would just waste their time going in loops. The same applies to test automation logic which also requires maintenance and debugging sometimes.

Naming conventions

All names in the code, whether they represent a function, class or a variable must be meaningful. Functions should be written using verbs and classes should be nouns. There shouldn’t be typographic errors, this goes without saying. Depending on the language you use, they should start with lower case or upper case letter. You should stick with the same pattern everywhere in your code. Abbreviations in names should be written with capital first letter and other lower case letters.

let a = 4; //bad

let circleRadius = 4; //good

function readPdfFile() //good

function readPDFFile() //bad

Functions names should show intent so the reader can understand what is the purpose of the function without reading the code. You should avoid duplicating the obvious information.

//bad

class User {
   string UserAddress;
   string UserName;
   string UserPhone;
}

//good

class User {
   string Address;
   string Name;
   string Phone;
}

Do not be bothered by the length of the name. Some names are naturally longer and it may seem awkward but if there is no better way to describe the function then this shouldn’t be a problem. It may happen that you come up with a better name later and this is perfectly fine. Names of classes, methods, properties and variables are subject to refactoring. The names of functions which return boolean values usually have names with is, are, does, etc. Avoid creating functions with grammatically incorrect names.

//good

isValid()

isEnabled()

hasAttribute()

//bad

isContainsNumber()

The functions should do one thing

This comes from SOLID principles of programming, but we will talk about SOLID some other time. It is a first principle of this acronym Single Responsibility Principle (SRP) which states that classes and functions should have just one responsibility. With classes it’s quite simple if you follow Page Object Model. It does not allow breaking of SRP.

What about functions? How to know that you are doing too much? If you follow the above principle of making meaningful names for functions and get in a situation where you need to put “and” in the function name, you overdid it. For example, if you have a function with name isEnabledAndVisible this is obviously breaking the SRP.

There should be a similar logic in your tests. Many assertion frameworks will not allow you to have multiple asserts in your tests. Actually, you can put multiple asserts but when the first one fails the rest of the test will not be executed. The test should test one thing only.

This rule, as any rule has exceptions. An example of such exception would be to input a value in a field and send enter key afterwards to remove the focus from the field. This function may be called inputTextAndEnter. It is required a bit of experience to know when to use such exception.

DRY or WET code

These two principles actually represent the eternal discussion should we allow repeating of our code. DRY says Don’t Repeat Yourself, while WET means Write Everything Twice. DRY is self-explanatory while WET usually means that writing duplicated code twice is fine, but if it turns out that you need to do it for the third time, you need to extract the code in a separate function. Obviously, this is again a matter of experience. Some pieces of code are deliberately left duplicated. For example if we have two functions which have parts of their body the same, but we know that the logic in one of them will change we will not extract this piece of code into separate function.

Refactor complex functions

Large functions should be decomposed in such way to be readable and maintainable. A good example is a date picker function which we use to select day, month and year in a specific control. This function would work with multiple dropdowns for year and month before finally selecting the day. We can write all this in a single function but it might be difficult to read.

clean code in test automation

Or we can separate each action in a specific function.

clean code in test automation

There is more code, but it is much better organized and easier to understand when it is divided like this,

Tests should be independent

Tests should not depend on each other. The test must not fail because of actions or lack of actions of another test. The order of the tests in the suite when they are executed must not matter. The tests should not depend on the type of browser they are executed in.

Assert messages must be descriptive

I know that not all assert libraries have the option to add custom failure message that you will see in the log when the assert fails. For those that do have this option, remember to make your assert messages specific for each assert. Pasting the same message for multiple assert will not help you find the failed assert in your code. On the other hand, if you have unique assert messages you can simply take the message from the log and search for it in the test and you will find the failing assert easily.

Waits should be thoughtfully implemented

With emerge of Cypress and Playwright I think people stopped paying (that much) attention to waits. Both of these tools have auto-implemented waits and although you have to occasionally call a wait function your code. Explicit timeouts are not a good idea anywhere. Cypress has option to wait for the request to complete which is a nice option.

cypress intercept and wait

Playwright has similar feature with WaitForURL (Playwright team should read this article, the part about naming the functions).

playwright wait

In addition to this both Playwright and Cypress have the configurable timeout for finding the element. You can specify for how long the tool should wait for the element before it decides to throw NoSuchElementException. You can read more in these pages for Playwright and Cypress respectively. Alternatively you can wait for a specific element state like Playwright documentation explains here.

Selenium on other hand has its well known waits. Implicit wait which affects the entire test suite and you can inadvertently change the timeout for all tests without wanting to do that. Usage of Thread.Sleep is considered a bad practice, although I have seen situations where nothing else helps and you are forced to use it. More about waits in Selenium you can find in this well built article.

Separate data from the tests

Ideally you want your tests to be able to run with unique data. You don’t want to use hard-coded data because of some database constraints and you don’t want to hold sensitive data in the tests. You want to have a single place for data in case something changes and you need to update the data. To avoid doing this in multiple tests, you can have the data in one place and feed it to the tests from there. Whether you will have a randomizer function, store data in external files or in some cases store them in environment variables it is up to you. A combination of these methods would probably be necessary.

Conclusion

Writing clean code is like an investment in your future time spending. You write clean code now so you don’t have to spend a lot time later to read and understand it. It is quite easy to write code. The compiler and interpreters will understand the code you wrote. The problem is in your colleagues, they might not understand it. Clean code in test automation is no different than any other code when it comes to rules. These rules must be applied, maybe in a different context but with the same purpose. The above article is not exhaustive. There are different rules for clean code, some of them were omitted from this article. Some of them are the subject for some other day.

Oh hi there 👋
It’s nice to meet you.

Sign up to receive awesome content in your inbox, every month.

We don’t spam! We keep your data private and share it only with third parties that make this service possible. Read our privacy policy for more info.

1 thought on “How To Achieve Clean Code In Test Automation?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.