Article

Most Important Things Automation Engineers Should Know

Dec 18, 2021

 

Do Not Use Record & Play in Real Projects

Most automation tools (especially commercial ones) have Record & Play functionality:
the ability to automatically record certain actions and then play them back just by clicking
on the Play button. The seeming simplicity of this functionality is a well-known trap for
novice software testers.
Record & Play looks very nice in advertising videos and presentations, but when you
actually work, such scripts are not recommended to be used, since they only complicate
the process. A recorded script does not use variables, loops, and conditions. Automatic
names of created procedures and functions are not usually informative, and all actions
are recorded in one function (which can be huge). Very often recorded lines of code are
so long that they do not fit on the screen.

 

Do Not Use Pauses

When you use any application, there are situations when you need to wait for the end
of an action, for example, reading data from the database, searching, loading all page
elements, etc.
In such cases, a recorded script “doesn’t know” that it is necessary to wait and tries to
perform further actions, although the application is not ready yet, and the result is a test
that fails with errors. Junior automation engineers use a pause in such cases:


sleep(5)


The wait time in this case is five seconds, and typically the timings are just
hardcoded approximations that are based on the current application speed.
Over time, such delays appear everywhere in the tests. And in that proliferation lies
the seeds of trouble.

Imagine that at some point the application starts to spend a little more time, and the
automation engineer has to make a huge number of hot fixes in a variety of tests. That
process is time consuming and error prone. After several similar, mass hot fixes the tester
comes to a new solution. He declares a global variable and uses it everywhere:


WAIT_TIME = 5
...
sleep(WAIT_TIME)

 

Now we just need to change the delay value in one place so that the wait time is
increased everywhere. This approach has one big disadvantage though. If the application
starts working faster, our tests will still wait for the same constant time. Since pauses are
placed in different places, the total time that the tests work will be much longer than it
could be.
The right solution in such cases is to wait for an object or object property. Any action
of the application ends with some event: a button that was previously disabled becomes
enable (for example, Next button), or a new control appears that was not previously
available. Or, on the contrary, some element or window can disappear from the screen
(for example, label “Wait for data loading”). Here we have to attach to such events using
wait functions. Now the code will look like this:

MAX_WAIT_TIME = 5
...
wait_for_object(object_name, timeout=MAX_WAIT_TIME)


Function wait_for_object can already be provided by the automation tool, or it will
have to be written by you. It checks the existence of the object with a certain interval
(for example, once per second) and returns true if the object appeared. If the object does
not appear within the time specified by the timeout parameter, the function returns false.
Thus, if the object we are interested in appears in a second, then the wait time will
be 1 second. If the object appears after 3 seconds, then the function will work only 3
seconds, etc.

 

Provide Exit by Timeout for Loops

Sometimes a test should be continued only after the occurrence of a certain event. For
example, we need to wait for a file to be created, so we code as follows:

while not file_exists()
{ /* do nothing*/ }

If for some reason the file is not created, the script will loop forever, which is clearly
not desirable. Therefore, in such situations it is necessary to provide a forced exit by a
timeout:

timeout = 10;
while not file_exists()
{
if timeout < 0
{ break; }
timeout--;
sleep(1);
}

In this example, we decrease the value of the timeout by 1 at each iteration and wait
for 1 second. After 10 seconds the value of timeout will be less than 0. As a result, we will
exit the loop using the break instruction, thus protecting ourselves from the infinite loop.
In addition, using the sleep instruction, we reduce the load on the processor. Verification
will be performed once per second, not thousands of times, as in the first example.
Perform an exit by timeout even in those cases when you are 100% sure that there
cannot be a hang-up – because most probably you are wrong.
It makes sense to define similar timeouts in the form of constants at the level of the
entire project, and not to set each time anew. For example, you can define two types of
timeout: short and long. A short timeout (usually equal to a few seconds) will be used
for operations that occur almost immediately, but it is necessary to wait for them to
finish: for example, creating a file or deleting a directory, an error message appearance
when you enter data incorrectly in a text box, and so on. A long timeout (usually equal to
several minutes) is intended to wait for the completion of data loading, the appearance of
a window, the response from the server, and so on.

 

Do Not Write Bulky Code

Try to follow the rule of “no more than three nested levels” when using conditions and
loops in tests. If you need to write code with a lot of nesting, then step back and think
about how to rewrite the code differently, for example, to bring a part of it into a separate
function, or to make two separate loops or conditions. Complex and confusing code looks
beautiful only when you write it, but not when you try to understand how it works.
Here is an example of code that already has one undesirable nested block:

for tbl in tables {
if table.name == "contacts"{
for col in table.columns {
/*enough nesting*/
if col.name == "first"
{
/*this block is redundant*/
print(col.name[0])
    }
 }
}
}

Code with the nesting of more than three blocks is very difficult to debug, especially
for a person who did not write it. When debugging such code, it is difficult to keep track of
the state of all variables. As a result, searching for a simple problem can take a lot of time.

Other Article

What is the Cucumber Scenario Outline?

A Powerful Tool for Efficient and Effective Test Automation

Gmail Automation using Selenium

Gmail Automation

Writing User Stories With Gherkin

Gherkin is a structured approach to writing behavioral tests

Background , Data Tables, Scenario Outlines

A background section in a feature file allows you to specify a set of steps that are common to every scenario in the file.

Most Important Things Automation Engineers Should Know

I mentioned here some of the common mistakes that automation engineers produce in their work, and ways to avoid those mistakes.

Database Testing - JDBC

We need to access Databases from outside(Intellij, Eclipse etc ) of SQL developer to test