首页 快讯正文

联博接口:python装饰器在接口自动化测试中的应用

admin 快讯 2020-05-25 61 1

在解说装饰器在接口自动化测试项目的应用之前,我们先来先容一下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’),最后输出了'打印一条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() 时,就会先打印'wrapper of decorator',然后输出'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')

类装饰器

类也可以作为装饰器。类装饰器主要依赖于函数__call__(),每当你挪用一个类的示例时,函数__call__()就会被执行一次。

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

...

这个类装饰器还不支持吸收参数,后面我们实战的装饰器时可以支持竣事参数的。

装饰器在接口自动化测试项目中应用

至此我们先容完了装饰器,下面我们基于之前的理论,来举行一次实战。

需求是希望通过装饰器来实现接口的请求,能够自界说请求方式、请求的根路径、公共参数、headers设置等功能。

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)

上面的header会被自动的添加的session的header里,common_params也会被添加到参数里,base_url和装饰器里传的url会被拼接成一个完整的url去请求接口。

以上实战的详细代码,固然这只是一部分,并不是完整的,后面争取写个系列文章,将这个接口自动化测试项目整体先容一下,迎接人人关注,多多交流!

迎接人人去 我的博客 瞅瞅,内里有更多关于测试实战的内容哦!!

,

Sunbet

www.tggzfm.com展望2019年,将用完善的服务体系,创新的技术应用,雄厚的资金实力,贴心的服务品质,成为Sunbet会员、代理的首选平台。

版权声明

本文仅代表作者观点,
不代表本站欧博网址的立场。
本文系作者授权发表,未经许可,不得转载。