Talking about how to improve the stability and maintainability of automated testing

Table of contents

Foreword:

Decorator and error retry mechanism

What are decorators?

Write a retry decorator on error

Implementation of error retry mechanism in pytest

Test case hierarchy in Allure

Why use a layered mechanism?

Allure's decorator @step


Foreword:

The stability and maintainability of automated testing are the key factors to ensure the effectiveness and continuity of testing work. Stability refers to the reliability and consistency of tests, while maintainability concerns the legibility, scalability, and maintainability of test scripts.

Decorator and error retry mechanism

When it comes to stability, what I have to say is the "error retry" mechanism. In automated testing, since the environment is generally a testing environment, there are often various convulsions that affect the test results. Stability brings challenges. After all, no one wants their scripts to have various unknown problems all day long, and often this kind of environmental convulsions (usually the response speed of the front-end page and the response speed of the back-end interface) bring The impact is temporary. It may fail in the last second, but you can execute it again in the next second. In this case, if you have an error retry mechanism, at least you can let your The script is safe and sound, let's talk about how to do it in detail.

What are decorators?

Because our approach relies on decorators, so before doing it, let's briefly introduce decorators.

​Decorator, in the form of adding a statement like @xxx above the method (or class), if we have implemented a decorator named retry, then we want to use it like this:

@retry
def test_login():
    print("test")
    error = 1/0

If retry implements an error and retry again (I will talk about how to implement it later), then if it is used in this way, the test_login case will be executed again when an error occurs.

It's amazing, let's take a look at the code that implements retry:

def retry(func):
    def warp():
        for time in range(3):
            try:
                func()
            except:
                pass
    return warp

As far as the result is concerned, the following code is executed:

@retry
def test_login():
    print("test")
    error = 1/0

test_login()

and execute:

retry(test_login)()

It is equivalent. From this we can see that the decorator is actually a function in essence. This function receives other functions (or classes) as parameters. By calling or modifying this function (or class), the original function to modify the functionality of that function.

There is another knowledge point here. Have you ever thought about how the function warp() inside retry gets the func parameter to execute? It is the warp function that executes the return of the retry function, and warp does not accept the parameter func.

This is the concept of closure in python. Closure refers to a function with its own context at runtime, such as the function warp here. When it runs, it comes with the function func passed to it by the upper-level function retry, so it can Func is processed and output at runtime.

After understanding decorators and closures, it is easy to implement the error retry mechanism for test cases below.

Write a retry decorator on error

Now, let's try to write an error retry decorator for test cases, the code is as follows:

def retry(times=3,wait_time=10):
    def warp_func(func):
        def fild_retry(*args,**kwargs):
            for t in range(times):
                try:
                    func(*args,**kwargs)
                    return 
                except:
                    time.sleep(wait_time)
        return fild_retry
    return warp_func

This decorator can implement a retry mechanism for the test case by passing in the number of retries (times) and the retry waiting time (wait_time).

Implementation of error retry mechanism in pytest

In the test framework pytest, the strategy of error retry has been implemented. We first need to install such a plug-in, and execute the following command in cmd to install:

pip install pytest-rerunfailures

If you need to apply this mechanism to all use cases, please use the following command when executing (reruns is the number of retries):

pytest --reruns 5

to execute your use case;

If you want to add the waiting time for error retry, please use the following command (reruns-delay is the waiting time):

pytest --reruns 5 --reruns-delay 1

to execute your use case;

If you want to apply retry strategy only to certain few test cases, you can use decorator:

@pytest.mark.flaky(reruns=5, reruns_delay=2)

For example:

@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_example():
    import random
    assert random.choice([True, False])

For a more detailed introduction, please refer to the official documentation  .

Test case hierarchy in Allure

We have just implemented the error retry mechanism of the use case, but this only solves the stability of the script in an unstable environment; if you want the script to become easier to maintain, in addition to the traditional po mode use case and element separation, We can also introduce a test case layering mechanism.

Why use a layered mechanism?

The traditional po mode only realizes the separation of use cases and elements, which guarantees the maintainability of use cases at a certain level. At least there is no need to worry about changing elements to make use cases invalid everywhere; but this is not enough. For example, there are now three cases, They all include the following steps: login, open the workbench, and enter the personal center; then if there is no layering, these three use cases will write all three steps. If one day the page changes and one of the steps needs to be changed , then you have to go to each use case to update that step.

And if we regard use cases as building blocks, and the three steps of logging in, opening the workbench, and entering the personal center are just building blocks, then when we write use cases, we only need to build up the building blocks when we use this step; If one day, the steps of one of the building blocks are changed, you only need to change the content of this building block, instead of changing it in every use case that uses this building block.

This greatly enhances the reusability and maintainability of use cases, which is why the layering mechanism is adopted. Next, I will introduce the layering mechanism in allure to discuss how to implement it.

Allure's decorator @step

​In allure, we can complete the layering mechanism through the decorator @step. Specifically, when you decorate a method with @step, when you execute this method in the use case, the decorated method will be displayed in the report ; and @step supports nested structure, which means that you can build your steps like building blocks, and they will all be displayed in the report one by one.

The following directly uses the official example of allure as an example:

import allure
import pytest

from .steps import imported_step


@allure.step
def passing_step():
    pass


@allure.step
def step_with_nested_steps():
    nested_step()


@allure.step
def nested_step():
    nested_step_with_arguments(1, 'abc')


@allure.step
def nested_step_with_arguments(arg1, arg2):
    pass


def test_with_imported_step():
    passing_step()
    imported_step()


def test_with_nested_steps():
    passing_step()
    step_with_nested_steps()

After running this case, the report looks like this:

image

As you can see,

test_with_nested_steps consists of two methods: passing_step() and step_with_nested_steps();

And step_with_nested_steps() is composed of nested_step();

nested_step() consists of nested_step_with_arguments(1, 'abc');

In this way, test cases are formed like building blocks; and in the report, the nested structure of steps is also clearly marked.

​In this way, we can compose test cases through one @step decoration method after another; at the same time, the report will also support hierarchical display; thus completing our hierarchical mechanism.

For more details about @step, please refer to the official documentation.

  As someone who has been here, I also hope that everyone will avoid some detours

Here I will share with you some necessities of the way forward in automated testing, hoping to help you.

(software testing related materials, automated testing related materials, technical questions and answers, etc.)

I believe it can make you better progress!

Click on the small card below

 

Guess you like

Origin blog.csdn.net/Free355/article/details/131764958