SoFunction
Updated on 2024-11-19

Steps to use interface testing with Python decorators

When writing interface cases, sometimes you need to do some common operations on the cae, the most typical scenarios such as: get the case execution time, print the log and so on.

Is there a way to centralize common operations so as to avoid writing the same code in every case (e.g. the same code to get execution time in every case)?

Python's decorators can do this.

Decorators can be understood in this way, decorators use closures to decorate the target function (the target function as a reference to a function external to the closure), that is, before and after the execution of the target function to execute some specified code to complete the desired business logic.

The concepts always seem obscure, so let's get straight to the grammar.

The first step is to look at the syntax of closures:

def outer(a):
    b = 10
    # inner is the inner function
    def inner():
        # Temporary variables from the outer function are used in the inner function #
        print(a + b)
    # The return value of the outer function is a reference to the inner function
    return inner

In the second step, take another look at the syntax of the decorator version of the closure:

There is only one difference from the closure example above: the reference to the external function in the closure is an integer a, whereas in this case it is a reference to a function (the reference to the function is also the function name).

# Decorators use the closure principle: the outer function defines an inner function, the inner function uses the outer function's local variables, and the outer function returns a reference to the inner function.
def outer(target):   # Decorator function Pass a reference to the target function you want to decorate, to be used in an inner function.
 b = 10
    c = 1
    d = 5
    # inner is the inner function
    def inner():
        print(b + c)
        # The argument target passed to the external function is a reference to the target function you wish to decorate.
        target()   # Here the target function is actually executed, want to decorate the function, so before and after the function to perform some operations, what operation depends on the business logic.
        print(c + d)
    # The return value of the outer function is a reference to the inner function
    return inner

Note: target is just a reference to the function (the reference points to the function's location in memory) and will not be executed. It is the function that is executed with () (target()).

As a final step, take another look at the syntax of the decorator:

@decorator
    def test_01():

So it can be summarized that: the decorator decorator is the outer function of the closure, i.e. outer() (the decorator is a function, i.e. the outer function of the closure), and the decorated function test_01 is the parameter passed to the closure, i.e. target.

An example:

Take the example of counting the time spent on requests for each interface.

Decorator ():

import time
def time_consume(func):
    def inner():
        time_start = ()  # Take a moment before the objective function starts
        print("\n interface request before the time is", time_start)
        func()
        time_end = ()  # Take a moment after the end of the objective function
        print("The time after the interface request is", time_end)
        t = time_end - time_start  # Calculate how long it took for the objective function to execute
        print("Interface Time Consumption:", t)
    return inner

interface (test_case.py):

import requests
import decorat
@decorat.time_consume
def test_demo():
    res = ("")
    assert res.status_code == 200

Effect:

To summarize the whole process of this example again:

'''
What @decorat.time_consume actually does is: test_demo = @decorat.time_consume(test_demo)
Since programming languages all parse execution from right to left, what happens to this code is:

1, the target function test_demo (is a variable name, which stores the reference to the target function) passed into the time_consume function, was received by the parameter func, then func is also the reference to the target function func and test_demo point to the same function object
2, time_consume function defines an internal function inner, in inner call func.
This uses the principle of closures (the closure principle: the outer function ends by binding a reference to itself to the inner function), and the outer function ends by binding func to the inner function for use by the inner function.
3, the end of the external function to create their own internal function of the reference inner return to test_demo to receive.
At this point, test_demo is no longer the original write the target function, test_demo can be understood as an instance of the inner function object, and then the execution of test_demo () is actually the execution of the inner () of an object
4. When test_demo() is executed again, it actually executes inner():
Execute fetch time first, print
It is the execution of func() afterwards that executes the target function, i.e., the execution of test_demo() itself
Finally take the time again and print the result

The Great White Way version:

Just one sentence, actually:
The decorated function is passed in as an argument to the decorator's external function, and the decorated function is executed in the decorator's internal function, with the addition of other code fragments A, the
This way the decorated function has its own logic as well as the logic of code fragment A in the inner function of the decorator. Making it unnecessary to modify the decorated function, the
then enhances the functionality of the decorated function.

Look at two more scenarios.

First: the decorated function has parameters

Normally the test_case of an interface test wouldn't want to be a function as mentioned in the example above, but would appear as a method of a class, for example:

The error log means that inner() needs 0 inputs, but 1 was passed in. This error proves the conclusion mentioned above.

The reason is that test_demo() has a parameter self, and inner() has no entry parameter defined. How can we solve this, by defining a mutable entry parameter for inner()? Let's look at the second problem first, and finally prove our conjecture together.

Second: the decorated function has a return value

The question arises, the return value prints None, because there is no variable in inner() to receive the return value of test_demo and return it? With the first question in mind, let's change the code.

Make 2 changes:

1、inner()define variable entry parameter

2. Define a variable in inner() to receive the return value of test_demo and return the variable.

The problem of test_case appearing as a method of a class is solved.

The return value is also printed normally.

The altered decorator can be used as a generic template for defining decorators, basically giving a wide variety of functions to decorate.

def decorat_demo(func):
    def inner(*args, **kwargs):   # inner() receives variable arguments
        # any code before # Define operations before the target function
        # Call the target function
        res = func(*args, **kwargs)  # Define variables to receive the return value of the target function
        # any code after # Define the operation after the target function
        return res     # Return the return value of the target function
    return inner

to this article on the use of Python decorator interface test steps to this article, more related python decorator interface test content please search my previous posts or continue to browse the following related articles I hope that you will support me in the future more!