【python做接口测试的学习记录day7——pytest自动化测试框架升级之规范yaml用例,接口关联】

之前的框架中存在的问题:

1、太多重复代码

2、可以将token关联写入yaml

因此我们需要对yaml进行规范

一、yaml规范

在根目录下创建“接口自动化测试框架YAML测试用例规范.txt”文件

  接口自动化测试YAML测试用例规范:
1、一级关键字必须包含name、request、validate
2、在request下必须包含method、url
3、传参方式:
   1.get请求,必须通过params传参
   2.post请求
        传json格式,需要使用json
        传表单格式,需要使用data传参
   3.文件上传,使用files传参
4、接口关联
  提取:
    1.正则表达式&jsonpath表达式
    extract:
           token1: '"token":"(.*?)"'  ##正则
           expires_in:$.expires_in    ##jsonpath
    取值方式:${token}

二、yaml用例文件

get_token.yaml

-
  name: 登录接口,获取接口统一鉴权码token接口
  request:
    method: post
    url: /jlcloud/api/login
    headers:
      'Content-Type': 'application/json'
    json: {"account": "admin","password": "123456","project": "DEFAULT",
           "teacherLogin":false,"clientId": "1","secret": "joylink"}
  extract:                   #这部分是提取token值,提取数据的方法需要写入提取该数据的接口yaml文件中,这里使用的是正则表达式的提取方法,如果接口的返回值是json,也可以使用jsonpath,将提取的值赋值给token,后续调用的时候使用${token}即可,其它的数据提取同理
    token: '"data":"(.*?)"'
  validate: None
-
  name: 登录接口,获取接口统一鉴权码token接口
  request:
    method: post
    url: /jlcloud/api/login
    headers:
      'Content-Type': 'application/json'
    json: {"account": "admin","password": " ","project": "DEFAULT",
           "teacherLogin":false,"clientId": "1","secret": "joylink"}
  extract:
    token: '"data":"(.*?)"'    #这部分是提取token值,提取数据的方法需要写入提取该数据的接口yaml文件中,这里使用的是正则表达式的提取方法,如果接口的返回值是json,也可以使用jsonpath,将提取的值赋值给token,后续调用的时候使用${token}即可,其它的数据提取同理
  validate: None

userinfo.yaml

-
  name: 获取用户信息接口
  request:
    method: get
    url: /jlcloud/api/login/getUserInfo
    params:
     token: ${token}
    headers:
      'Content-Type': 'application/json'
  validate: None

三、框架升级

我们按照这样的规范,在request_util.py中写入规范yaml的方法,替换值的方法,统一请求的封装

我们直接上代码:

import jsonpath
import requests
import json
from common.yaml_util import YamlUtil
from builtins import str
import re


class RequestUtil:

    def __init__(self,two_node):
        self.base_url=YamlUtil().read_config('base',two_node)


    #替换值的方法
    # #(替换url,params,data,json,headers)
    # #(string,int,float,list,dict)
    def replace_value(self, data):
        if data:
            # 保存数据类型
            data_type = type(data)
            # 判断数据类型转换成str
            if isinstance(data, dict) or isinstance(data, list):
                str_data = json.dumps(data)
            else:
                str_data = str(data)
            for cs in range(1, str_data.count('${') + 1):
                # 替换
                if "${" in str_data and "}" in str_data:
                    start_index = str_data.index("${")
                    end_index = str_data.index("}", start_index)
                    old_value = str_data[start_index:end_index + 1]
                    new_value = YamlUtil().read_yaml(old_value[2:-1])
                    str_data = str_data.replace(old_value, new_value)
            # 还原数据类型
            if isinstance(data, dict) or isinstance(data, list):
                data = json.loads(str_data)
            else:
                data = data_type(str_data)
        return data


    #规范yaml测试用例
    def standard_yaml(self,caseinfo):
        caseinfo_keys= caseinfo.keys()
        #判断一级关键字是否包含:name,request,validate
        if "name" in caseinfo_keys and "request" in caseinfo_keys and "validate" in caseinfo_keys:
            #判断request下面是否包含:method、url
            request_keys=caseinfo["request"].keys()
            if "method" in  request_keys and "url" in request_keys:
                print("yaml基本架构检查通过")
                method = caseinfo['request'].pop("method") #pop() 函数用于移除列表中的一个元素,并且返回该元素的值。
                url= caseinfo['request'].pop("url")
                res = self.send_request(method,url,**caseinfo['request']) #caseinfo需要解包加**
                return_text=res.text
                # 提取值并写入extract.yaml文件
                if "extract" in caseinfo.keys():
                    for key, value in caseinfo["extract"].items():
                        if "(.*?)" in value or "(.+?)" in value:  # 正则表达式
                            zz_value = re.search(value, return_text)
                            if zz_value:
                                extract_value = {key: zz_value.group(1)}
                                YamlUtil().write_yaml(extract_value)
                        else:  # jsonpath
                            try:
                                resturn_json = res.json()
                                js_value = jsonpath.jsonpath(resturn_json, value)
                                if js_value:
                                    extract_value = {key: js_value[0]}
                                    YamlUtil().write_yaml(extract_value)
                            except Exception as e:
                                print("extract返回的结果不是JSON格式,不能使用jsonpath提取")
                return res
            else:
                print("在request下必须包含method,url")
        else:
            print("一级关键字必须包含name,request,validate")



    sess= requests.session()

    # 统一请求封装

    def send_request(self,method,url,**kwargs):
        method=str(method).lower()  #转换小写
        #基础路径的拼接和替换
        url= self.base_url + self.replace_value(url)
        print(url)
        #参数替换
        for key,value in kwargs.items():
            if key in ['params','data','json','headers']:
                kwargs[key]=self.replace_value(value)
            elif key == "files":
                for file_key, file_path in value.items():
                    value[file_key] = open(file_path, 'rb')
        res = RequestUtil.sess.request(method, url, **kwargs)
        print(res.text)
        return res

四、测试用例的简化

基于我们对框架的改造升级,接下来就可以省去用例中重复的代码,我们的用例被简化,每个用例只需要更换yaml数据的读取名称即可,test_login.py代码如下:

import pytest
import requests
import json
from common.request_util import RequestUtil
from common.yaml_util import YamlUtil

class TestRequest:
    pass
    @pytest.mark.parametrize("caseinfo",YamlUtil().read_testcase('get_token.yaml'))
    def test_login(self,caseinfo):
        res = RequestUtil("base_test_url").standard_yaml(caseinfo)

    #
    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('userinfo.yaml'))
    def test_userinfo(self, caseinfo):
        res = RequestUtil("base_test_url").standard_yaml(caseinfo)
    #     print(res.text)
    #
    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('city_type.yaml'))
    def test_simulation(self, caseinfo):
        res = RequestUtil("base_test_url").standard_yaml(caseinfo)

你可能感兴趣的:(功能测试,python,pytest,自动化,测试工具)