API 接口自动化测试详细图文教程学习系列16--项目实战演练3

测试学习记录,仅供参考!

项目实战演练-封装方法

从yaml文件读取接口信息发起请求

1、 修改项目根目录 unit_tools 软件包文件下"sendrequests.py"文件内容;

  • 先导包引入 unit_tools 软件包下"handle_data"软件包"yaml_handler.py"文件中的 "read_yaml" 读取 yaml 文件数据方法;

  • 再测试验证调用读取 yaml 文件数据方法读取到指定的目标信息;

  • 然后自定义各个变量拿到所需要的数据值;

  • 最后实例化 SendRequests 类,调用类里面的方法,依次传入请求地址 url、请求方式 method、请求头和请求参数;

    引入模块--导包

    import requests
    from requests import utils
    import re
    from unit_tools.handle_data.yaml_handler import read_yaml

    使用类的方式去封装--定义一个类 SendRequests

    class SendRequests:
    # 使用 init 创建构造函数
    def init(self):
    # 占位符
    pass

    复制代码
      # 类方法 加上 @classmethod 就是一个类方法
      # 类方法不能去访问实例 初始化构造函数里面的属性,只能访问类的属性--需要把 self 改为 cls
      @classmethod
      # 定义一个方法 _text_encode --传一个接口返回的文本格式 res_text
      def _text_encode(cls, res_text):
          """
          处理接口返回值出现unicode编码时  例如:\\u767b
          :param res_text:
          :return:
          """
          # 调用 re.search --去搜索这个文本(匹配正则表达式),第二个参数是接口的返回值res_text
          match = re.search(r"\\u[0-9a-fA-F]{4}", res_text)
          # 判断匹配的结果是否存在
          if match:
              # 当匹配的结果存在时,把接口的返回值进行处理转换--先把它转码然后再解码
              result = res_text.encode().decode('unicode_escape')
          else:
              # 若不存在,则直接把接口的返回值传过来
              result = res_text
          # 最后return
          return result
    
      # 直接封装一个 send_request 方法--给它传一个可变数量的参数 **kwargs
      def send_request(self, **kwargs):
          # 创建一个会话--使用 requests.Session() 调用这个类并把它的结果返回出去
          # 把创建的这个会话对象返回赋值给 session
          session = requests.Session()
          # 定义一个变量response并赋值为空
          response = None
          # 这里最好再添加一个异常处理
          try:
              # 直接session.调用request()把可变数量参数**kwargs给它传进来,返回赋值给 response
              response = session.request(**kwargs)
              # 通过调用requests这个模块--通过接口的返回值 response.cookies
              # 通过接口的返回对象获取cookies--定义变量set_cookie去接收
              set_cookie = requests.utils.dict_from_cookiejar(response.cookies)
              # 判断是否有这个cookie
              if set_cookie:
                  print(f'获取到Cookies: {set_cookie}')
              # 调用self._text_encode方法--结果返回值response.text
              res = self._text_encode(response.text)
              print(res)
          # 连接异常 requests.exceptions.ConnectionError
          except requests.exceptions.ConnectionError:
              print("接口请求异常,可能是request的链接数过多或者速度过快导致程序报错!")
          # 请求异常
          except requests.exceptions.RequestException as e:
              print(f'请求异常,请检查系统或数据是否正常!错误信息为:{e}')
          # 把发起接口请求的结果返回出去
          return response
    
      # 再定义一个方法 execute_api_request--再来封装一个方法
      # 这里传的参数比较多,一部分是data.yaml配置文件中的字段,最终根据request里面所需要的参数
      # api_name, url, method, header--yaml配置文件;case_name--自定义;
      # cookie默认为空,file文件上传,这里也传空;最后再传可变数量参数 **kwargs
      def execute_api_request(self, api_name, url, method, header, case_name, cookie=None, file=None, **kwargs):
          """
          发起接口请求
          :param api_name: 接口名称--后续打印日志会用到
          :param url: 接口地址
          :param method: 请求方法
          :param header: 请求头
          :param case_name: 测试用例名称--后续打印日志会用到
          :param cookie: cookie
          :param file: 文件上传
          :param kwargs: 未知数量的关键字参数
          :return:
          """
          # 直接使用self.调用上面封装的方法send_request()
          # 传参格式,这里的关键字务必跟request里面的关键字参数一致
          # 关键字要接收的参数值是 上面定义的这个函数execute_api_request中的 参数,
          # 需要哪个传给哪个,一一对应即可--再把未知数量传参**kwargs给放进来
          # timeout=10--接口超时设置10秒;verify=False--忽略HTTPS证书校验,默认verify=None
          # 最后把结果给返回出去并赋值给 response
          response = self.send_request(method=method, url=url, headers=header, cookies=cookie, files=file, timeout=10,
                                       verify=False, **kwargs)
          # 使用 return 直接返回结果
          return response

    这里使用登录接口进行测试验证

    if name == 'main':
    # 调用引用的模块里面的read_yaml()方法--相对路径 .././datas/login.yaml
    # 再拿到列表中的第一组元素--ps:不确定时可以打印出来详细查看
    data = read_yaml('.././datas/login.yaml')[0]
    # 地址--可以看到列表里面又嵌套了一个字典--使用键值对的方式取相对应的 key 值
    url = data['baseInfo']['url']
    # 请求方法 同样依次取 key 值
    method = data['baseInfo']['method']
    # 请求头 同样依次取 key 值--一般都会需要请求头,除非特殊处理
    header = data['baseInfo']['header']
    # 入参--找到与baseInfo同级的testCase进行取值--testCase里面是一个列表--它里面只有一组数据--取对应值data
    req_data = data['testCase'][0]['data']

    复制代码
      # 查看校验封装的方法能不能正常运行--SendRequests() 实例化这个类--把结果返回出去给自定义的变量对象 send
      send = SendRequests()
      # 这里传上面刚刚定义的变量 地址 url、请求方式 method、表头 header、入参 req_data
      # 这里请求头在接口中已特殊处理过,一般情况下都是需要正常传递的
      res = send.execute_api_request(api_name=None, url=url, method=method, header=None, case_name=None,
                                     data=req_data)
      print(res)

2、此时运行 sendrequests.py 文件,可以看到控制台信息有提示"请求异常",这是因为 yaml 文件中对应的 url 信息(url: /dar/user/login)只写了接口地址,请求地址 url 里面没有传服务器 IP 地址;

如若不清楚所读取目标文件数据信息,可自行调试打印查看其目标数据是什么格式,是怎么的数据信息;查看成功后别忘记"注释掉"或者"删除";

复制代码
if __name__ == '__main__':
    # 调用引用的模块里面的read_yaml()方法--相对路径 .././datas/login.yaml
    # 再拿到列表中的第一组元素--ps:不确定时可以打印出来详细查看
    data = read_yaml('.././datas/login.yaml')[0]
    print(f'项目根目录datas目录文件login.yaml文件中数据信息data: {data}')
    # 地址--可以看到列表里面又嵌套了一个字典--使用键值对的方式取相对应的 key 值
    url = data['baseInfo']['url']
    print(f'请求地址url: {url}')
    # 请求方法 同样依次取 key 值
    method = data['baseInfo']['method']
    print(f'请求方式method: {method}')
    # 请求头  同样依次取 key 值--一般都会需要请求头,除非特殊处理
    header = data['baseInfo']['header']
    print(f"请求头header: {header}")
    # 入参--找到与baseInfo同级的testCase进行取值--testCase里面是一个列表--它里面只有一组数据--取对应值data
    req_data = data['testCase'][0]['data']
    print(f"请求参数req_data: {req_data}")

    # 查看校验封装的方法能不能正常运行--SendRequests() 实例化这个类--把结果返回出去给自定义的变量对象 send
    send = SendRequests()
    # 这里传上面刚刚定义的变量 地址 url、请求方式 method、表头 header、入参 req_data
    # 这里请求头在接口中已特殊处理过,一般情况下都是需要正常传递的
    res = send.execute_api_request(api_name=None, url=url, method=method, header=None, case_name=None,
                                   data=req_data)
    print(res)

3、再次修改 sendrequests.py 文件内容,目前暂时使用字符串进行拼接,后续如有需要可以再写入配置文件里面;

复制代码
# 引入模块--导包
import requests
from requests import utils
import re
from unit_tools.handle_data.yaml_handler import read_yaml


# 使用类的方式去封装--定义一个类 SendRequests
class SendRequests:
    # 使用 __init__ 创建构造函数
    def __init__(self):
        # 占位符
        pass

    # 类方法 加上 @classmethod 就是一个类方法
    # 类方法不能去访问实例 初始化构造函数里面的属性,只能访问类的属性--需要把 self 改为 cls
    @classmethod
    # 定义一个方法 _text_encode --传一个接口返回的文本格式 res_text
    def _text_encode(cls, res_text):
        """
        处理接口返回值出现unicode编码时  例如:\\u767b
        :param res_text:
        :return:
        """
        # 调用 re.search --去搜索这个文本(匹配正则表达式),第二个参数是接口的返回值res_text
        match = re.search(r"\\u[0-9a-fA-F]{4}", res_text)
        # 判断匹配的结果是否存在
        if match:
            # 当匹配的结果存在时,把接口的返回值进行处理转换--先把它转码然后再解码
            result = res_text.encode().decode('unicode_escape')
        else:
            # 若不存在,则直接把接口的返回值传过来
            result = res_text
        # 最后return
        return result

    # 直接封装一个 send_request 方法--给它传一个可变数量的参数 **kwargs
    def send_request(self, **kwargs):
        # 创建一个会话--使用 requests.Session() 调用这个类并把它的结果返回出去
        # 把创建的这个会话对象返回赋值给 session
        session = requests.Session()
        # 定义一个变量response并赋值为空
        response = None
        # 这里最好再添加一个异常处理
        try:
            # 直接session.调用request()把可变数量参数**kwargs给它传进来,返回赋值给 response
            response = session.request(**kwargs)
            # 通过调用requests这个模块--通过接口的返回值 response.cookies
            # 通过接口的返回对象获取cookies--定义变量set_cookie去接收
            set_cookie = requests.utils.dict_from_cookiejar(response.cookies)
            # 判断是否有这个cookie
            if set_cookie:
                print(f'获取到Cookies: {set_cookie}')
            # 调用self._text_encode方法--结果返回值response.text
            res = self._text_encode(response.text)
            print(res)
        # 连接异常 requests.exceptions.ConnectionError
        except requests.exceptions.ConnectionError:
            print("接口请求异常,可能是request的链接数过多或者速度过快导致程序报错!")
        # 请求异常
        except requests.exceptions.RequestException as e:
            print(f'请求异常,请检查系统或数据是否正常!错误信息为:{e}')
        # 把发起接口请求的结果返回出去
        return response

    # 再定义一个方法 execute_api_request--再来封装一个方法
    # 这里传的参数比较多,一部分是data.yaml配置文件中的字段,最终根据request里面所需要的参数
    # api_name, url, method, header--yaml配置文件;case_name--自定义;
    # cookie默认为空,file文件上传,这里也传空;最后再传可变数量参数 **kwargs
    def execute_api_request(self, api_name, url, method, header, case_name, cookie=None, file=None, **kwargs):
        """
        发起接口请求
        :param api_name: 接口名称--后续打印日志会用到
        :param url: 接口地址
        :param method: 请求方法
        :param header: 请求头
        :param case_name: 测试用例名称--后续打印日志会用到
        :param cookie: cookie
        :param file: 文件上传
        :param kwargs: 未知数量的关键字参数
        :return:
        """
        # 直接使用self.调用上面封装的方法send_request()
        # 传参格式,这里的关键字务必跟request里面的关键字参数一致
        # 关键字要接收的参数值是 上面定义的这个函数execute_api_request中的 参数,
        # 需要哪个传给哪个,一一对应即可--再把未知数量传参**kwargs给放进来
        # timeout=10--接口超时设置10秒;verify=False--忽略HTTPS证书校验,默认verify=None
        # 最后把结果给返回出去并赋值给 response
        response = self.send_request(method=method, url=url, headers=header, cookies=cookie, files=file, timeout=10,
                                     verify=False, **kwargs)
        # 使用 return 直接返回结果
        return response


# 这里使用登录接口进行测试验证
if __name__ == '__main__':
    # 调用引用的模块里面的read_yaml()方法--相对路径 .././datas/login.yaml
    # 再拿到列表中的第一组元素--ps:不确定时可以打印出来详细查看
    data = read_yaml('.././datas/login.yaml')[0]
    # 地址--可以看到列表里面又嵌套了一个字典--使用键值对的方式取相对应的 key 值
    # url = data['baseInfo']['url']
    url = 'http://127.0.0.1:8787' + data['baseInfo']['url']
    # 请求方法 同样依次取 key 值
    method = data['baseInfo']['method']
    # 请求头  同样依次取 key 值--一般都会需要请求头,除非特殊处理
    header = data['baseInfo']['header']
    # 入参--找到与baseInfo同级的testCase进行取值--testCase里面是一个列表--它里面只有一组数据--取对应值data
    req_data = data['testCase'][0]['data']

    # 查看校验封装的方法能不能正常运行--SendRequests() 实例化这个类--把结果返回出去给自定义的变量对象 send
    send = SendRequests()
    # 这里传上面刚刚定义的变量 地址 url、请求方式 method、表头 header、入参 req_data
    # 这里请求头在接口中已特殊处理过,一般情况下都是需要正常传递的
    res = send.execute_api_request(api_name=None, url=url, method=method, header=None, case_name=None,
                                   data=req_data)
    print(res)

再次修改后运行就没有问题了,请求成功,能够获取到所需要的响应结果信息;

如若运行 sendrequests.py 文件时,会报连接异常"接口请求异常,可能是request的链接数过多或者速度过快导致程序报错!",得启动测试项目接口服务;

把所需要的字段写入到指定的目标文件中

在获取响应结果数据信息成功后,需要把对应的 "token"值和"userId"值写入指定的文件中(目标文件自定义,例如:项目根目录下的 yaml 文件 extract.yaml ),操作步骤如下:

  • 继续引入 unit_tools 软件包下 handle_data 软件包 yaml_handler.py 文件中的 "write_yaml" 写入 yaml 文件数据方法;就是读取和写入方法均导入了;

  • 再接着把响应结果返回值字符串格式转换为 JSON 格式,转换成功后获取对应的 token 值和 userId 值(这里 token 值是随机的,而 userId 值则是固定的,具体建议可根据实际接口返回);

  • 最后使用 write_yaml 方法写入到目标指定文件里面;

    引入模块--导包

    import requests
    from requests import utils
    import re
    from unit_tools.handle_data.yaml_handler import read_yaml, write_yaml

    使用类的方式去封装--定义一个类 SendRequests

    class SendRequests:
    # 使用 init 创建构造函数
    def init(self):
    # 占位符
    pass

    复制代码
      # 类方法 加上 @classmethod 就是一个类方法
      # 类方法不能去访问实例 初始化构造函数里面的属性,只能访问类的属性--需要把 self 改为 cls
      @classmethod
      # 定义一个方法 _text_encode --传一个接口返回的文本格式 res_text
      def _text_encode(cls, res_text):
          """
          处理接口返回值出现unicode编码时  例如:\\u767b
          :param res_text:
          :return:
          """
          # 调用 re.search --去搜索这个文本(匹配正则表达式),第二个参数是接口的返回值res_text
          match = re.search(r"\\u[0-9a-fA-F]{4}", res_text)
          # 判断匹配的结果是否存在
          if match:
              # 当匹配的结果存在时,把接口的返回值进行处理转换--先把它转码然后再解码
              result = res_text.encode().decode('unicode_escape')
          else:
              # 若不存在,则直接把接口的返回值传过来
              result = res_text
          # 最后return
          return result
    
      # 直接封装一个 send_request 方法--给它传一个可变数量的参数 **kwargs
      def send_request(self, **kwargs):
          # 创建一个会话--使用 requests.Session() 调用这个类并把它的结果返回出去
          # 把创建的这个会话对象返回赋值给 session
          session = requests.Session()
          # 定义一个变量response并赋值为空
          response = None
          # 这里最好再添加一个异常处理
          try:
              # 直接session.调用request()把可变数量参数**kwargs给它传进来,返回赋值给 response
              response = session.request(**kwargs)
              # 通过调用requests这个模块--通过接口的返回值 response.cookies
              # 通过接口的返回对象获取cookies--定义变量set_cookie去接收
              set_cookie = requests.utils.dict_from_cookiejar(response.cookies)
              # 判断是否有这个cookie
              if set_cookie:
                  print(f'获取到Cookies: {set_cookie}')
              # 调用self._text_encode方法--结果返回值response.text
              res = self._text_encode(response.text)
              print(res)
          # 连接异常 requests.exceptions.ConnectionError
          except requests.exceptions.ConnectionError:
              print("接口请求异常,可能是request的链接数过多或者速度过快导致程序报错!")
          # 请求异常
          except requests.exceptions.RequestException as e:
              print(f'请求异常,请检查系统或数据是否正常!错误信息为:{e}')
          # 把发起接口请求的结果返回出去
          return response
    
      # 再定义一个方法 execute_api_request--再来封装一个方法
      # 这里传的参数比较多,一部分是data.yaml配置文件中的字段,最终根据request里面所需要的参数
      # api_name, url, method, header--yaml配置文件;case_name--自定义;
      # cookie默认为空,file文件上传,这里也传空;最后再传可变数量参数 **kwargs
      def execute_api_request(self, api_name, url, method, header, case_name, cookie=None, file=None, **kwargs):
          """
          发起接口请求
          :param api_name: 接口名称--后续打印日志会用到
          :param url: 接口地址
          :param method: 请求方法
          :param header: 请求头
          :param case_name: 测试用例名称--后续打印日志会用到
          :param cookie: cookie
          :param file: 文件上传
          :param kwargs: 未知数量的关键字参数
          :return:
          """
          # 直接使用self.调用上面封装的方法send_request()
          # 传参格式,这里的关键字务必跟request里面的关键字参数一致
          # 关键字要接收的参数值是 上面定义的这个函数execute_api_request中的 参数,
          # 需要哪个传给哪个,一一对应即可--再把未知数量传参**kwargs给放进来
          # timeout=10--接口超时设置10秒;verify=False--忽略HTTPS证书校验,默认verify=None
          # 最后把结果给返回出去并赋值给 response
          response = self.send_request(method=method, url=url, headers=header, cookies=cookie, files=file, timeout=10,
                                       verify=False, **kwargs)
          # 使用 return 直接返回结果
          return response

    这里使用登录接口进行测试验证

    if name == 'main':
    # 调用引用的模块里面的read_yaml()方法--相对路径 .././datas/login.yaml
    # 再拿到列表中的第一组元素--ps:不确定时可以打印出来详细查看
    data = read_yaml('.././datas/login.yaml')[0]
    # 地址--可以看到列表里面又嵌套了一个字典--使用键值对的方式取相对应的 key 值
    # url = data['baseInfo']['url']
    url = 'http://127.0.0.1:8787' + data['baseInfo']['url']
    # 请求方法 同样依次取 key 值
    method = data['baseInfo']['method']
    # 请求头 同样依次取 key 值--一般都会需要请求头,除非特殊处理
    header = data['baseInfo']['header']
    # 入参--找到与baseInfo同级的testCase进行取值--testCase里面是一个列表--它里面只有一组数据--取对应值data
    req_data = data['testCase'][0]['data']

    复制代码
      # 查看校验封装的方法能不能正常运行--SendRequests() 实例化这个类--把结果返回出去给自定义的变量对象 send
      send = SendRequests()
      # 这里传上面刚刚定义的变量 地址 url、请求方式 method、表头 header、入参 req_data
      # 这里请求头在接口中已特殊处理过,一般情况下都是需要正常传递的
      res = send.execute_api_request(api_name=None, url=url, method=method, header=None, case_name=None,
                                     data=req_data)
    
      # 这里res的结果返回值response.text--它打印的是一个text属于字符串,字符串不能通过key值去取--所以需要先转换成一个json格式
      res_json = res.json()
      # 转换成功之后即可获取它的token值
      token = res_json['token']
      # 获取它的userId
      user_id = res_json['userId']
      # 调用write_yaml()方法写入文件
      write_yaml({'token': token, 'userId': user_id})

运行 sendrequests.py 文件成功后,查看需要写入到的指定目标(extract.yaml)文件;

如若多次执行 sendrequests.py 文件,则会多次写入,出现重复的数据,后续可考虑优化;

未完待续。。。

相关推荐
ID_180079054731 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
时空系2 小时前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
复利人生 复利日知录 赋能循环2 小时前
2026年复利精进:我的每日觉醒与成长密码
学习·思维模型·知识复利·复利·独立
sakiko_2 小时前
UIKit学习笔记4-使用UITableView制作滚动视图
笔记·学习·ios·swift·uikit
CHANG_THE_WORLD3 小时前
python 批量终止进程exe
开发语言·python
liann1193 小时前
3.2_红队攻击框架--MITRE ATT&CK‌
python·网络协议·安全·网络安全·系统安全·信息与通信
云天AI实战派3 小时前
AI 智能体问题排查指南:ChatGPT、API 调用到 Agent 上线失灵的全流程修复手册
大数据·人工智能·python·chatgpt·aigc
晓梦林3 小时前
MAZESEC-X1靶场学习笔记
笔记·学习
我的xiaodoujiao4 小时前
API 接口自动化测试详细图文教程学习系列15--项目实战演练2
python·学习·测试工具·pytest