在讲解装饰器在接口自动化测试项目的应用之前,我们先来介绍一下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去请求接口。

以上实战的具体代码,当然这只是一部分,并不是完整的,后面争取写个系列文章,将这个接口自动化测试项目整体介绍一下,欢迎大家关注,多多交流!

欢迎大家去 我的博客 瞅瞅,里面有更多关于测试实战的内容哦!!

python装饰器在接口自动化测试中的应用的更多相关文章

  1. python装饰器,迭代器,生成器,协程

    python装饰器[1] 首先先明白以下两点 #嵌套函数 def out1(): def inner1(): print(1234) inner1()#当没有加入inner时out()不会打印输出12 ...

  2. Python 装饰器装饰类中的方法

    title: Python 装饰器装饰类中的方法 comments: true date: 2017-04-17 20:44:31 tags: ['Python', 'Decorate'] categ ...

  3. python装饰器中@wraps作用--修复被装饰后的函数名等属性的改变

    Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的de ...

  4. 使用python requests库写接口自动化测试--记录学习过程中遇到的坑(1)

    一直听说python requests库对于接口自动化测试特别合适,但由于自身代码基础薄弱,一直没有实践: 这次赶上公司项目需要,同事小伙伴们一起学习写接口自动化脚本,听起来特别给力,赶紧实践一把: ...

  5. 使用 JsonPath 完成接口自动化测试中参数关联和数据验证(Python语言)

    背景: 接口自动化测试实现简单.成本较低.收益较高,越来越受到企业重视 restful风格的api设计大行其道 json成为主流的轻量级数据交换格式 痛点: 接口关联 也称为关联参数.在应用业务接口中 ...

  6. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  7. python 装饰器、递归原理、模块导入方式

    1.装饰器原理 def f1(arg): print '验证' arg() def func(): print ' #.将被调用函数封装到另外一个函数 func = f1(func) #.对原函数重新 ...

  8. 装饰模式和python装饰器

    装饰器和装饰模式 先给出两者的定义: - 装饰器:装饰器是一个非常著名的设计模式,常常被用于有切面需求的场景.较为经典的有插入日志.性能測试.事务处理等. 装饰器是解决这类问题的绝佳设计.有了装饰器, ...

  9. Python装饰器使用技巧

    装饰器 装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试 ...

随机推荐

  1. Elasticsearch 集群部署

    本文部署环境 $ cat /etc/redhat-release CentOS Linux release (Core) 部署前系统优化 $ /etc/security/limits.conf roo ...

  2. thinkphp--多个id查询

    $feedback_list = $feedback -> where( array("member_id"=>array("in", " ...

  3. tp5--model的坑

    先上代码: class Article extends Model { //获取全部文章 public function getArticleAll($id,$page) { $cate = new ...

  4. Cent OS 7 搭建MySQL

    搭建数据库服务器 版本众多,但为了追求稳定选择的是5.7 在使用YUM REPOSITORY官方给出的版本如下: The MySQL Yum repository includes the lates ...

  5. QFileDialog::getOpenFileName() hangs

    https://forum.qt.io/topic/49209/qfiledialog-getopenfilename-hangs-in-windows-when-using-the-native-d ...

  6. DiskPart.exe and managing Virtual Hard Disks (VHDs) in Windows 7

    coreygoOctober 7, 2009 In Windows 7, new commands have been added in DiskPart to allow for the creat ...

  7. java 之 构造器 static关键字

    构造器  特点: 方法名和类名一至,没有void没有返回,无参数的称为无参构造器,有参数的称为有参构造器 语法: public 类名 {数据类型 参数名} 目的:创建对象 注意:如果类中没有带有参数的 ...

  8. 【Linux常见命令】date命令

    Linux date命令:可以用来显示或设定系统的日期与时间. 在显示方面,使用者可以设定欲显示的格式,格式设定为一个加号后接数个标记,其中可用的标记列表如下: 时间方面: %H : 小时(00..2 ...

  9. Tomcat的设置4——Tomcat的体系结构与设置基于端口号的虚拟主机

    一.Tomcat体系结构 从conf/server.xml可体现Tomcat的体系.一个Server可有多个service,一个service可以有多个连接器connector,每个连接器暴露出不同的 ...

  10. Node Mysql事务处理封装

    node回调函数的方式使得数据库事务貌似并没有像java.php那样编写简单,网上找了一些事务处理的封装并没有达到自己预期的那样简单编写,还是自己封装一个吧.封装的大体思路很简单:函数接受一个事务处理 ...