当前位置:首页 > 技术分析 > 正文内容

Python-接口自动化装饰器的大用处

事情是这样,我们正在编写接口自动化用例。因为基本上都是复杂的场景测试。

例如测试支付业务的过程:

  1. 用户登录
  2. 加入购物
  3. 下单
  4. 支付

也就是说,如果你想测试支付业务,大概必须要调用前面三个接口。那么我们就需要把前面三个接口进行封装。以用户登录为例。

import json
import requests


class UserLogin:

    def __init__(self, username, password):
        self.username = username
        self.password = password

    def get_token(self):
        """获取用户登录token"""
        url = "http://httpbin.org/post"

        data = {
            "username": self.username,
            "password": self.password,
            "token": "token123"  # 假装这是接口返回的toKen
        }
        r = requests.post(url, data=data)

        if r.status_code != 200:
            raise ValueError("接口请求失败")
        
        try:
            r.json()
        except json.decoder.JSONDecodeError:
            raise ValueError("接口不是json格式")

        if r.json()["headers"]["Host"] != "httpbin.org":
            raise ValueError("接口返回必要参数错误")
        
        token = r.json()["form"]["token"]
        return token


if __name__ == '__main__':
    user_login = UserLogin("zhangsan", "mima123")
    token = user_login.get_token()
    print(token)

单看接口这么封装,貌似没有问题~!但每个接口调用之后都需要经历以下过程:

  1. 判断状态码是否为 200,如果不是 200 说明接口不通。
  2. 仅接着判断返回值格式是否为 JSON,如果不是,你就无法提取数据。
  3. 检查接口返回的必要参数,例如:r.json()["headers"]["Host"]
  4. 提取接口返回的数据。例如: r.json()["form"]["token"]

python装饰器

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他有助于让我们的代码更简短,也更Pythonic。

这里就不领着大家一步步推演如何创建一个装饰器,直接看例子。

  • 装饰器
def dec():
    """
    python装饰器
    """
    def decorator(func):
        
        def wrapper(*args, **kwargs):
            func_name = func.__name__
            print(f"被装饰的方法名: {func_name}")
            print(f"方法的入参 args: {args}")
            print(f"方法的入参 kwargs: {kwargs}")

            r = func(*args, **kwargs)
            print(f"方法的返回值 return: {r}")

        return wrapper

    return decorator

装饰器的架子大概长这个样子,重点在装饰器的入参和返回值。

  • 用法

@dec()
def add(a, b):
    c = a + b
    return c


add(1, 2)

调用@dec()装饰器来装饰一个add() 函数

运行结果

被装饰的方法名: add
方法的入参 args: (1, 2)
方法的入参 kwargs: {}
方法的返回值 return: 3

这个装饰器可以拿到被装饰函数的名字入参返回值,是不是很有意思。

接口检查装饰器

  • check_response() 装饰器实现
import json
from jmespath import search


def check_response(
        describe: str = "",
        status_code: int = 200,
        ret: str = None,
        check: dict = None,
        debug: bool = False):
    """
    checkout response data
    :param describe: interface describe
    :param status_code: http status code
    :param ret: return data
    :param check: check data
    :param debug: debug Ture/False
    :return:
    """
    def decorator(func):
        def wrapper(*args, **kwargs):
            func_name = func.__name__
            if debug is True:
                print(f"Execute {func_name} - args: {args}")
                print(f"Execute {func_name} - kwargs: {kwargs}")

            r = func(*args, **kwargs)
            flat = True
            if r.status_code != status_code:
                print(f"Execute {func_name} - {describe} failed: {r.status_code}")
                flat = False

            try:
                r.json()
            except json.decoder.JSONDecodeError:
                print(f"Execute {func_name} - {describe} failed:Not in JSON format")
                flat = False

            if debug is True:
                print(f"Execute {func_name} - response:\n {r.json()}")

            if flat is True:
                print(f"Execute {func_name} - {describe} success!")

            if check is not None:
                for expr, value in check.items():
                    data = search(expr, r.json())
                    if data != value:
                        print(f"Execute {func_name} - check data failed:{value}")
                        raise ValueError(f"{data} != {value}")

            if ret is not None:
                data = search(ret, r.json())
                if data is None:
                    print(f"Execute {func_name} - return {ret} is None")
                return data
            else:
                return r.json()

        return wrapper

    return decorator
  1. 核心就是在前面@dec() 装饰器的架子上扩展,增加参数和返回值校验。
  2. 代码引用了jmespath 库,主要是为了提取数据。
  • 使用
import requests

class UserLogin:

    def __init__(self, username, password):
        self.username = username
        self.password = password

    @check_response("获取用户登录token", 200, ret="form.token", check={"headers.Host": "httpbin.org"}, debug=True)
    def get_token(self):
        """获取用户登录token"""
        url = "http://httpbin.org/post"

        data = {
            "username": self.username,
            "password": self.password,
            "token": "token123"  # 假装是接口返回的toKen
        }
        r = requests.post(url, data=data)
        return r


if __name__ == '__main__':
    user_login = UserLogin("zhangsan", "mima123")
    token = user_login.get_token()
    print(token)

通过@check_response() 装饰被调用接口,可以极大的简化代码。参数说明:

  • 获取用户登录token: 接口描述。
  • 200: 检查接口返回值状态码是否为 200
  • ret="form.token": 提取接口返回值中的token,通过jmespath
  • check={"headers.Host": "httpbin.org"}: 检查接口返回值中包含的参数。相当于对接口数据进行断言。
  • debug=True: 开启debug,打印详细信息,方便调试。

运行信息

Execute get_token - args: (<__main__.UserLogin object at 0x000001EF4397E1C0>,)
Execute get_token - kwargs: {}
Execute get_token - response:
 {'args': {}, 'data': '', 'files': {}, 'form': {'password': 'mima123', 'token': 'token123', 'username': 'zhangsan'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '49', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.25.0', 'X-Amzn-Trace-Id': 'Root=1-62682337-2cd21bd0599368e54d2063bd'}, 'json': None, 'origin': '173.248.248.88', 'url': 'http://httpbin.org/post'}
Execute get_token - 获取用户登录token success!
token123

有了这个小小的装饰器,我们减少了很多相同的样例代码。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/4701.html

标签: kwargs.get
分享给朋友:

“Python-接口自动化装饰器的大用处” 的相关文章

vue3中父子传值、defineProps用法、defineEmits用法

Vue3中新增了一个 script setup 语法糖模式,可以在单文件组件中更简洁地编写组件逻辑。使用 script setup 语法后,props、data、computed、methods 等选项不再需要独立定义,而是可以直接在 setup 函数中声明,代码结构更加清晰,并且可以更方便地使用响...

带你五步学会Vue SSR

作者:liuxuan 前端名狮转发链接:https://mp.weixin.qq.com/s/6K6GUHcLwLG4mzfaYtVMBQ前言SSR大家肯定都不陌生,通过服务端渲染,可以优化SEO抓取,提升首页加载速度等,我在学习SSR的时候,看过很多文章,有些对我有很大的启发作用,有些就只是照搬官...

理解virt、res、shr之间的关系(linux系统篇)

前言想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存。这里我们可以看到VIRT、RES和SHR三个重要的指标,他们分别代表什么意思呢?这是本文需要跟大家一起探讨的问题。...

jvm疯狂吃内存,到底是谁的锅?

jvm应该是每一个java程序员都需要掌握的内容,但是在没有遇到问题之前,很多都是基于理论的,唯有实战才能增加个人的知识储备。本文是从一个角度来分析是谁在狂吃内存,希望对你有所帮助。本文是易观技术人员注意到一台开发机上各个微服务进程占用内存很高,随即便展开了调查......ps:本文来源于:http...

多项修正 尼康D4s发布最新1.10版固件

尼康公司与2014年8月27日发布了D4s的最新固件,固件版本号为C:1.10。这次固件升级,主要解决了一些BUG,并且对拍摄菜单与相机操作做了一定调整。下面是本次新固件的具体信息:尼康发布D4s最新C固件 1.10版对C固件升级到1.10版所作的修改:当选定运动VR模式并换上 AF-S 尼克尔 4...

Vue进阶(二十六):详解router.push()

在Vue2.0路由跳转中,除了使用 <router-link> 声明式创建 a 标签来定义导航链接,还可以借助 router 的实例方法,通过编码式编写代码来实现。router.push(location)想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 hi...