インターフェイス自動化テストにおける Python デコレータの適用

目次

序文:

デコレーター

関数のいくつかのプロパティ

シンプルなデコレータ

糖衣構文 @

パラメータ付きのデコレータ

デコレータはパラメータも受け取ることができます

クラスデコレータ

デコレーターはインターフェース自動化テストプロジェクトに適用されます


序文:

Python デコレータはインターフェイス自動テストで広く使用されています。デコレータは、関数の定義を変更せずに関数の動作を変更または拡張するために使用できる特別な Python 構文です。インターフェイス自動テストでは、デコレータを使用して、ロギング、例外処理、パフォーマンス統計などの追加機能を追加できます。

インターフェース自動テストプロジェクトにおけるデコレーターの適用を説明する前に、まず Python デコレーターとは何かを紹介しましょう。

デコレーター

デコレータと言えば第一級市民として関数を挙げなければなりませんが、Python では関数にはいくつかの特徴があるので、まずはそれを理解しましょう。

関数のいくつかのプロパティ
  • 関数はオブジェクトです

Python では、関数もオブジェクトであり、次のような関数を変数に割り当てることができます。

def func(message):
    print("打印一条message: {}".format(message))

send_message = func
send_message("123")

関数 func を変数 send_message に割り当てたので、send_message を呼び出した後は、関数 func() を呼び出したのと同じになります。

  • パラメータとして機能する

関数は、パラメータとして別の関数に渡すこともできます。次に例を示します。

def func(message):
    print("打印一条message: {}".format(message))

def call_func(func, message):
    func(message)
  • 関数の入れ子

関数のネストとは、次のように関数内に別の関数を定義することを意味します。

def call_func(message):
    def func(message):
        print("打印一条message: {}".format(message))
    return func(message)

上記はcall_func内に関数funcを定義し、この内部関数をcall_func内で呼び出し、呼び出し後のcall_funcの戻り値として返しています。

  • 関数の戻り値は関数オブジェクトにすることもできます

上記の例を変更してみましょう。次のように:

def call_func():
    def func(message):
        print("打印一条message: {}".format(message))
    return func

result = call_func()
result("hello world")

関数 call_func() の戻り値は関数オブジェクト func そのもので、それを変数 result に代入して result('hello world') を呼び出し、最後に 'print a message: hello world' を出力します。

シンプルなデコレータ
def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

def greet():
    print('hello world')

greet = my_decorator(greet)
greet()

# 输出
wrapper of decorator
hello world

変数greetは内部関数wrapper()を指しており、内部関数wrapper()は元の関数greet()を呼び出します。したがって、最後にgreet()を呼び出すと、最初に「デコレータのラッパー」が出力され、次に「hello world」を出力します。ここでの関数 my_decorator() はデコレータであり、実際に実行する必要がある関数greet()をラップして動作を変更しますが、元の関数greet()は変更されません。

糖衣構文 @
def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

@my_decorator
def greet():
    print('hello world')

greet()

ここでの @ は糖衣構文と呼ばれ、@my_decorator は前のgreet=my_decorator(greet) ステートメントと同等ですが、より簡潔です。したがって、プログラム内に同様に装飾する必要がある他の関数がある場合、その関数の上に @decorator を追加するだけで済み、関数の再利用とプログラムの可読性が大幅に向上します。

パラメータ付きのデコレータ

装飾された関数がデコレータで実行されるため、元の関数greet()がパラメータを受け取る必要がある場合、関数によって受け取られたパラメータをデコレータに渡す必要があります。どうすればよいでしょうか? これは非常に簡単で、デコレータのネストされた関数にパラメータを追加するだけです。

def my_decorator(func):
    def wrapper(message):
        print('wrapper of decorator')
        func(message)
    return wrapper


@my_decorator
def greet(message):
    print(message)


greet('hello world')

# 输出
wrapper of decorator
hello world

ただし、一々書くのは一般的ではないので面倒ですが、次のようにしてください。

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper
デコレータはパラメータも受け取ることができます

デコレータには柔軟性もあり、自身で定義されたパラメータを受け入れたり、パラメータをデコレータ自体に渡すこともできます。

def repeat(num):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                print('wrapper of decorator')
                func(*args, **kwargs)
        return wrapper
    return my_decorator


@repeat(4)
def greet(message):
    print(message)

greet('hello world')

クラスデコレータ

クラスはデコレータとしても機能します。クラス デコレータは主に、クラスのインスタンスを呼び出すたびに1 回実行される関数呼び出し( )に依存します。

class Request:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print('num of calls is: {}'.format(self.num_calls))
        return self.func(*args, **kwargs)

@Request
def example():
    print("hello world")

example()

# 输出
num of calls is: 1
hello world

example()

# 输出
num of calls is: 2
hello world

...

このクラス デコレータはまだパラメータの受信をサポートしていませんが、後で実際のデコレータで終了パラメータをサポートできるようになります。

デコレーターはインターフェース自動化テストプロジェクトに適用されます

ここまでデコレーターの紹介でしたが、先ほどの理論に基づいて実戦を行っていきます。

要件は、デコレータを通じてインターフェイスのリクエストを実装し、リクエスト メソッド、リクエストのルート パス、パブリック パラメータ、ヘッダー設定、およびその他の機能をカスタマイズできることです。

class Request:

    def __init__(self, url='', method='get'):
        ''''''
        self.url = url  # 请求路径
        self.method = method # 请求方法
        self.func_return = None # 被装饰器标记的方法的返回参数
        self.func_im_self = None  # 被装饰器标记的方法的类的实例
        self.session = None # 当前使用的会话对象

    def __call__(self, func):
        self.func = func
        self.is_class = False
        try:
            if inspect.getfullargspec(self.func).args[0] == 'self':
                self.is_class = True
        except IndexError:
            pass

        def fun_wrapper(*args, **kwargs):
           # 调用被装饰标记的方法,这个方法会返回请求接口所需要的返回值
            self.func_return = self.func(*args, **kwargs) or {}
            self.func_im_self = args[0] if self.is_class else object
            self.create_url()
            self.create_session()
            self.session.headers.update(getattr(self.func_im_self, 'headers', {}))
            self.decorator_args.update(getattr(self.func_im_self, 'common_params', {}))
            self.decorator_args.update(self.func_return)
            return Request(self.method, self.url, self.session)
        return fun_wrapper
def create_url(self):
    """
    生成http请求的url,跟路径和接口路由进行拼接
    """
    base_url = getattr(self.func_im_self, 'base_url', '')
    self.url = self.func_return.pop('url', None) or self.url
    self.url = ''.join([base_url, self.url])

使用する場合は、次のようなクラスを定義する必要があります。

class AdvertService:

    def __init__(self):
        self.common_params = {} # 定义接口请求的公共参数
        self.headers = {} # 定义请求的header
        self.base_url = self._config.AD_ADMIN_ROOT_URL

    @Request(url=“/v3/advert/create”, method='post')
    def _create_ad(self, advert: Advert):
        return dict(json=advert)

上記のヘッダーはセッション ヘッダーに自動的に追加され、common_params もパラメーターに追加され、base_url とデコレーターに渡された URL が完全な URL に結合されてインターフェイスをリクエストします。

  ここに来た者として、皆さんも寄り道は避けていただきたいと思います。

ここでは、自動テストを進める上で必要なことをいくつか共有し、お役に立てれば幸いです。

(WEB自動テスト、アプリ自動テスト、インターフェース自動テスト、継続的インテグレーション、自動テスト開発、工場面接の大きな質問、履歴書テンプレートなど)

そうすることでより良い進歩が見込めると信じています!

下の小さなカードをクリックしてください

おすすめ

転載: blog.csdn.net/Free355/article/details/131701164