之前我们的框架中,如果有多个测试用例,则需要在yaml文件中写入多个用例,而每个用例可能不同的仅仅只是个别参数值,这就导致很多重复代码,现在我们使用数据驱动就可以解决这个问题了。

我依旧采用之前的登录接口为例,简单记录一下数据驱动封装的全过程

一、DDT数据驱动yaml文件

在根目录下创建包datas,用来存放我们的数据驱动yaml文件,在datas下新建一个get_token_data.yaml文件,作为我们登录接口的数据驱动文件

# DDT(data driver test)数据驱动yaml文件,对应的yaml测试用例文件为:get_token.yaml
- ['name','account','password','project','assert_str']
- ['登录成功获取token','admin','014f4041514bc5dcb82845fe5efa3c54','DEFAULT','data']
- ['登录失败密码错误','admin','123456','DEFAULT',40003]
- ['登录失败密码为空','admin','','DEFAULT',501]

第一行写入参数名称,后面你有几个用例就将用例对应的参数值写上,我这里写了用例名称、账户、密码、项目和断言,这里的参数名需要在之前的yaml用例文件中调用,因此我们修改下之前的get_token.yaml文件,如下:

-
  name: $ddt{name}
  parameterize:
    name-account-password-project-assert_str: /datas/get_token_data.yaml
  request:
    method: post
    url: /jlcloud/api/login
    headers:
      'Content-Type': 'application/json'
    json:
      account: $ddt{account}
      password: $ddt{password}
      project: $ddt{project}
      teacherLogin: false
      clientId: "1"
      secret: "test"
  extract:
    token: '"data":"(.*?)"'
  validate:
    - equals: {status_code: 200}
    - contains: $ddt{assert_str}

在yaml中调用的格式是$ddt{参数名},并且需要写入数据驱动 parameterize:
    name-account-password-project-assert_str: /datas/get_token_data.yaml

驱动你这个用例的数据的读取,前面是参数,后面是读取的数据路径。

二、封装读取的方法

在common包下创建parameterize_util.py文件,这里需要写入我们读取的方法,并且我们在yaml_util中的读取测试用例的方法也需要写入到这里(在yaml_util.py中剪切read_testcase粘贴到parameterize_util.py),我们需要对这个这个方法加个判断,保证当用例大于等于2条也是可以使用的(即没使用数据驱动的多条用例yaml文件)

import json
from common.yaml_util import YamlUtil
import os
import yaml


# 读取测试用例
def read_testcase(yaml_name):
    with open(os.getcwd() + '\\testcases\\' + yaml_name, mode='r', encoding='utf-8') as f:
        caseinfo = yaml.load(f, yaml.FullLoader)
        if len(caseinfo)>=2:   #判断yaml用例文件中有几条用例,当用例大于等于2时,直接返回caseinfo
            return caseinfo
        else:                    #当等于1时,因为数据驱动后的caseinfo是字典列表我们就需要对caseinfo解包
            if "parameterize" in dict(*caseinfo).keys():
                new_caseinfo = ddt(*caseinfo)
                return new_caseinfo
            else:
                return caseinfo


def ddt(caseinfo):
    if "parameterize" in caseinfo.keys():
        caseinfo_str = json.dumps(caseinfo)  # 判断parameterize是否在caseinfo中
        for param_key, param_value in caseinfo["parameterize"].items():
            key_list = param_key.split("-")  # 将param_key转成列表
            data_list = YamlUtil().read_data(param_value)  # 读取param_value
            # 规范yaml数据文件的写法
            length_flag = True
            for data in data_list:
                if len(data) != len(key_list):
                    length_flag = False
                    break
            # 替换值
            new_caseinfo = []
            if length_flag:
                for x in range(1, len(data_list)):  # 循环数据的行数
                    temp_caseinfo = caseinfo_str
                    for y in range(0, len(data_list[x])):  # 循环数据列
                        if data_list[0][y] in key_list:
                            # 替换原始的yaml里面的$ddt{}
                            if isinstance(data_list[x][y], int) or isinstance(data_list[x][y], float):
                                temp_caseinfo = temp_caseinfo.replace('"$ddt{' + data_list[0][y] + '}"',
                                                                      str(data_list[x][y]))
                            else:
                                temp_caseinfo = temp_caseinfo.replace("$ddt{" + data_list[0][y] + "}",
                                                                      str(data_list[x][y]))
                    new_caseinfo.append(json.loads(temp_caseinfo))
        return new_caseinfo
    else:
        return caseinfo

三、接口用例文件

这里因为read_testcase的方法不在yaml_util中了,所以我需要从common.parameterize_util 导入 ddt,read_testcase的方法并且调用,所以修改了test_login.py文件,代码如下:

import pytest
from common.request_util import RequestUtil
from test import Test
from common.parameterize_util import ddt,read_testcase

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

    @pytest.mark.parametrize("caseinfo", read_testcase('userinfo.yaml'))
    def test_userinfo(self, caseinfo):
        RequestUtil("base_test_url", Test()).standard_yaml(caseinfo)

    @pytest.mark.parametrize("caseinfo", read_testcase('city_type.yaml'))
    def test_city(self, caseinfo):
       RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)

    @pytest.mark.parametrize("caseinfo", read_testcase('mapid.yaml'))
    def test_mapid(self, caseinfo):
        RequestUtil("base_test_url", Test()).standard_yaml(caseinfo)

四、需要注意的

    当后面的接口需要调用登录接口返回的token值,我们可以在数据驱动yaml文件中使用${read_extract_data(token)}调用,例如我的userinfo接口的yaml数据驱动文件:

# DDT(data driver test)数据驱动yaml文件,对应的yaml测试用例文件为:userinfo.yaml
- ['name','token','assert_str']
- ['正确token成功获取用户信息','${read_extract_data(token)}','data']
- ['错误token无法获取用户信息','1', 40004]

在userinfo.yaml中直接使用$ddt{token}即可 

-
  name: $ddt{name}
  parameterize:
    name-token-assert_str: /datas/userinfo_data.yaml
  request:
    method: get
    url: /jlcloud/api/login/getUserInfo
    params:
     token: $ddt{token}
    headers:
      'Content-Type': 'application/json'
  validate:
    - equals: { status_code: 200 }
    - contains: $ddt{assert_str}

这样就完成了我们的数据驱动封装,在以后添加修改测试用例只需要在datas包下,修改数据驱动yaml文件即可。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐