• pytest + yaml 框架 -6.hooks 钩子功能实现


    前言

    在发送请求的时候,我们希望在发送请求参数前,带上签名的值,或者返回的内容需要二次处理,解密后返回。
    此功能我们可以用 hooks 钩子来实现
    pip 安装插件

    pip install pytest-yaml-yoyo
    
    • 1

    hooks 功能在v1.0.4版本上实现

    response 钩子功能

    requests 库只支持一个 response 的钩子,即在响应返回时可以捎带执行我们自定义的某些方法。
    可以用于打印一些信息,做一些响应检查或想响应对象中添加额外的信息

    # 作者-上海悠悠 微信/QQ交流:283340479
    # blog地址 https://www.cnblogs.com/yoyoketang/
    import requests
    url = 'https://httpbin.org/get'
    
    
    def response_status(resopnse, *args, **kwargs):
        print('url', resopnse.url)
        resopnse.status = 'PASS' if resopnse.status_code < 400 else 'FAIL'
    
    
    res = requests.get(url, hooks={'response': response_status})
    print(res.status)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    以上是基于requests 库的钩子功能实现的基本方式

    yaml 用例中添加response 钩子

    在yaml 文件中添加response 钩子功能,跟上面代码方式差不多, 有2种方式

    • 1.写到config 全局配置,每个请求都会带上hooks
    • 2.写到单个请求的request 下,仅单个请求会带上hooks功能

    先看单个请求的response 钩子
    test_hook1.yml

    # 作者-上海悠悠 微信/QQ交流:283340479
    # blog地址 https://www.cnblogs.com/yoyoketang/
    config:
      name: post示例
    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
        hooks:
          response: ['hook_response']
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在conftest.py 中注册钩子函数

    # 作者-上海悠悠 微信/QQ交流:283340479
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    def hook_response(response, *args, **kwargs):
        # print(response.text) 原始数据
        print("执行response hook 函数内容....")
        class NewResponse:
            text = '{"code": 0, "data": {"token": "yo yo"}}'  # response.text解密
            history = response.history
            headers = response.headers
            cookies = response.cookies
            status_code = response.status_code
            raw = response.raw
            is_redirect = response.is_redirect
            content = b'{"code": 0, "data": {"token": "yo yo"}}'  # response.text解密
            elapsed = response.elapsed
    
            @staticmethod
            def json():
                # 拿到原始的response.json() 后解码
                return {"code": 0, "data": {"token": "yo yo"}}
    
        return NewResponse
    
    my_builtins.hook_response = hook_response
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    由于上面用例只在第一个请求中使用了hooks功能,所以第二个请求的断言- eq: [$.code, 0] 会失败

    钩子方法调用语法

    • 1.层级是在request 下
    • 2.hooks 关键字对应的是一个字典 {“response”: []}
    • 3.response 的值可以是单个函数名称,也可以是多个func1, func2,或者是一个list类型[func1, func2]
    • 4.response 的值必须是一个可以调用的函数,此函数需在conftest 中注册绑定到my_builtins 模块
    • 5.调用的函数第一个参数是response, 可以重写response内容(如需要对返回结果解密),也可以不用重写
      request:
        method: POST
        url: http://httpbin.org/post
        hooks:
          response: ['hook_response']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    config 全局使用

    在config 中配置全局hooks功能,格式如下

    config:
      name: post示例
      hooks:
        response: ['hook_response']
    
    • 1
    • 2
    • 3
    • 4

    test_hook2.yml完整示例

    config:
      name: post示例
      hooks:
        response: ['hook_response']
    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
        hooks:
          response: ['hook_response']
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    全局配置hooks, 那么该用例下所有的请求都会带上hooks

    请求预处理钩子

    如果需要对请求参数预处理,我们还新增了一个request 请求钩子,可以获取到发送请求时的request参数

    在conftest.py

    # 作者-上海悠悠 微信/QQ交流:283340479
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    
    def func1(req):
        print(f'请求预处理:{req}')
        
        
    def func2():
        print(f'请求预处理-----------')
        
        
    my_builtins.func1 = func1
    my_builtins.func2 = func2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在 yaml 文件中使用示例

    config:
      name: post示例
    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
        hooks:
          request: ['func1', 'func2']
          response: ['hook_response']
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
        hooks:
          response: ['hook_response']
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$.code, 0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在config 中设置全局hooks示例

    config:
      name: post示例
      hooks:
        request: ['func1', 'func2']
        response: ['hook_response']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    由于request 变量是pytest的一个内置fixture,此变量保留着,获取请求参数的函数使用req 代替。
    利用request hook功能可以实现请求参数的预处理,比如请求body签名和加密处理等需求。

  • 相关阅读:
    cx3588 Recovery HDMI 没显示
    VS中属性页各种包含目录的区别
    115 不同的子序列
    记一次断电引起的CentOS引导失败
    mybatis的xml中<trim>标签的用法
    因为一行Log日志导致的线上P1事故
    SaaS系统平台赋能大健康产业互联网变革,助力企业提升市场占有率
    Vue 2 中的 render()函数和 JSX 语法,根据`路由配置中meta`中的`keepAlive`属性,判断是否需要`keep-alive`
    C++中的运算符重载
    猿创征文 |【算法入门必刷】数据结构-栈(四)
  • 原文地址:https://blog.csdn.net/qq_27371025/article/details/128125937