使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 22--数据驱动--参数化处理 Json 文件

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

数据驱动

结合 pytest 框架参数化处理对测试用例做参数化;这里介绍 Json 格式文件、yaml 格式文件、Excel 格式文件 三种文件方式去做测试用例参数化;自行根据喜好选择一种做参数化;

一、使用Json文件对测试用例做参数化

JSON是一种轻量级的数据交互格式,采用完全独立于编程语言的文本格式来存储和表示数据,本质上是一个带有特定格式的字符串。JSON负责不同编程语言中的数据传递和交互,类似国际通用语言中的英语。

各种编程语言存储数据的容器不尽相同,在Python中有字典dict这样的数据类型,而其它语言可能没有对应的字典。为了让不同的语言都能够相互通用的互相传递数据,JSON就是一种非常良好的中转数据格式。

JSON数据的格式
基本结构

JSON是一个键值对(key/value)的集合。

键:必须是字符串类型

值:可以是字符串、数字、布尔值、数组、其他对象(即嵌套的键值对集合)以及null

有两种基本结构,对象(Object)和数组(Array)。

键值对集合(对象):表示为{"key":value}

值的有序列表(数组):表示为[value1,value2]

数据类型

JSON支持以下几种数据类型:字符串(String)、数字(Number)、对象(Object)、数组(Array)、布尔值(true/false)、null

格式规范

必须以开头的{[开始,并以对应的}] 结尾

所有的键名必须是双引号括起来的字符串

数组和对象中的元素或成员之间用逗号 ,分隔,最后一个元素或成员后面可以有或没有逗号,但建议不加,以保持一致性。

JSON格式数据转化
序列化

使用json.dumps()函数可以将Python对象序列化为JSON格式的字符串。

反序列化

使用json.loads()函数可以将JSON格式的字符串反序列化为Python对象。

注意事项

JSON字符串必须使用双引|号,单引号无效

Python的json 模块默认不处理中文ASCll编码,需要ensure_ascii=False

JSON没有日期类型,日期通常转为字符串处理

JSON不支持注释

尾随逗号在JSON中无效(如{"a":1,})

代码展示

1、在项目根目录 data 目录文件下新建名称为 login.json 的 json 文件,注意格式,里面要带列表,因为 pytest 框架参数化要带有可迭代的对象;需注意 json 文件中的引号要是 "2" 双引号,若是 '1' 单引号的话则会报错;

2、数据格式最外层是列表,里面嵌套字典;

复制代码
[
  {
    "username": "admin123",
    "password": "123456"
  },
  {
    "username": "admin123456",
    "password": "123456"
  },
  {
    "username": "admin123",
    "password": "123456789"
  },
  {
    "username": "",
    "password": ""
  }
]

3、写了 json 格式的数据后,得去写一个文件去读取 json 的数据;

4、在项目根目录 util_tools 软件包下新建名称为 handle_data(处理数据的类都放在这下面) 的软件包,在 handle_data 软件包下新建名称为 operateJson.py(处理 json 文件) 的 Python 文件;专门处理 json 文件;

json 文件读取比较简单,第一步,把 json 模块导进来,这里不需要再封装类;

直接自定义一个函数 def read_json() 里面传一个参数(读取哪个 json 文件的路径);

一个点'.'代表当前文件;

一个点加一个斜杠'./'代表当前文件的目录;

两个点'..'代表当前目录的上一级目录;

点(.)的含义‌:

  • 点(.)代表当前目录。它是一个特殊的符号,用于指示当前工作目录的位置。
  • 例如,当你执行cd .命令时,实际上并没有改变当前目录,因为.就是当前目录的指代。

双点(..)的含义‌:

  • 双点(..)代表当前目录的上一级目录,也就是父目录。它允许你在文件系统中向上导航。

    import json

    def read_json(file_path):
    """
    读取json的数据
    :param file_path: 文件路径
    :return:
    """
    with open(file_path, 'r', encoding='utf-8') as file:
    data = json.load(file)
    return data

    调试查看--注意相对路径和绝对路径的区别

    res = read_json('../../data/login.json')
    print(res)

5、 运行查看结果;

复制代码
[{'username': 'admin123', 'password': '123456'}, {'username': 'admin123456', 'password': '123456'}, {'username': 'admin123', 'password': '123456789'}, {'username': '', 'password': ''}]

进程已结束,退出代码为 0

6、改造读取 json 的文件,优化 operateJson.py 文件内容,增加列表推导式;

1)、[for data_dict in data]:列表推导式 for 循环读取 data_dict(字典) 去循环这个 data;

2)、[tuple() for data_dict in data]:通过 tuple() 这个去把它转换成元组;

3)、因为它 data_dict(自定义名称) 这个数据循环之后是如下一组数据,它是一个字典;

例如:{'username': 'admin123', 'password': '123456'}

4)、[tuple(data_dict.values()) for data_dict in data]:可以直接通过字典去读取它的 values 值;

5)、data_list_tuple = [tuple(data_dict.values()) for data_dict in data]:最终把结果给返回出去;

6)、return data_list_tuple:把结果返回出去;

复制代码
import json

def read_json(file_path):
    """
    读取json的数据
    :param file_path: 文件路径
    :return: 返回列表类型,列表里面是元组数据,如:[('admin123','123456'),(),(),()......]
    """
    with open(file_path, 'r', encoding='utf-8') as file:
        data = json.load(file)
        data_list_tuple = [tuple(data_dict.values()) for data_dict in data]
    return data_list_tuple

# 调试查看--注意相对路径和绝对路径的区别
res = read_json('../../data/login.json')
print(res)

7、增加列表推导式运行成功之后可以查看结果,已经符合需要的数据格式要求;

对比 login.json 文件内容看,一组数据只抽取键值;

复制代码
[('admin123', '123456'), ('admin123456', '123456'), ('admin123', '123456789'), ('', '')]

进程已结束,退出代码为 0

8、把 json 文件的数据处理成符合要求的格式之后,可以在测试用例中做参数化了;

9、优化 operateJson.py 文件,注释一下或删除不需要的;

复制代码
import json

def read_json(file_path):
    """
    读取json的数据
    :param file_path: 文件路径
    :return: 返回列表类型,列表里面是元组数据,如:[('admin123','123456'),(),(),()......]
    """
    with open(file_path, 'r', encoding='utf-8') as file:
        data = json.load(file)
        data_list_tuple = [tuple(data_dict.values()) for data_dict in data]
    return data_list_tuple

10、优化 test_login.py 文件,添加参数化;

1)、 导包引入读取 json 文件的 def read_json(file_path): 方法,导入 pytest 库;

2)、使用 @pytest.mark.parametrize() 装饰器做参数化,第一个(参数)是接收后面一个可迭代参数(第二个参数)内容的参数,第一个参数 data(自定义名称),第二个参数 通过调用读取 json 文件 read_json() 方法,里面传路径文件参数,注意文件路径,在当前文件调试查看和在主函数 run.py 文件运行路径是不同的,因为最终是在主函数运行('./data/login.json');

3)、username, password = data :使用 username、password 两个变量接收元组解包数据;

data 是元组数据,[('admin123', '123456'), ('admin123456', '123456'), ('admin123', '123456789'), ('', '')]

4)、login_page.login(username, password):使用参数化数据传参;

复制代码
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
from util_tools.handle_data.operateJson import read_json

class TestLogin:

    # 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例
    @pytest.mark.parametrize('data', read_json('./data/login.json'))
    # 用一个 data(需与上面保持一致) 参数去接收参数化数据
    def test_login_success(self, get_driver, data):
        # 进行元组解包--通过两个参数去接收元组中的每一组数据
        username, password = data
        # 传浏览器对象--再把结果返回
        login_page = LoginPage(get_driver)
        # 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)
        login_page.login(username, password)
        # 断言结果
        success_ele = get_driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
        assert success_ele != ''
        sleep(2)

11、运作 run.py 主函数文件查看结果;

12、 添加'异常处理'和'日志打印',优化 operateJson.py 文件;

复制代码
import json
from util_tools.logs_util.recordlog import logs

def read_json(file_path):
    """
    读取json的数据
    :param file_path: 文件路径
    :return: 返回列表类型,列表里面是元组数据,如:[('admin123','123456'),(),(),()......]
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            data = json.load(file)
            data_list_tuple = [tuple(data_dict.values()) for data_dict in data]
        return data_list_tuple
    except Exception as e:
        logs.error(f'读取Json文件异常,异常原因为:{e}')
补充:

参考文档官网:https://docs.python.org/zh-cn/3/library/json.html

四种方法 json.dumps json.dump json.loads json.load

json.dumps 编码:将字典或者列表转换为json格式的字符串。

json.loads 解码:将json格式字符串转换为python对象。且JSON对象必须是str、bytes或bytearray,而不是list。

json.dump :将字典或者列表转换为json格式的字符串并且写入到文件中。

json.load :从文件中读取json格式的字符串并且转换为python对象。

转换为字符串

json.dumps()

复制代码
# 导包--导入库
import json
# json.dumps 可以将python列表转换成字符串
jsontr = json.dumps(['hello word',{'a':'b'}])
# 打印查看--转换成字符串有什么好处--可以把数据直接写入到文件里面
print(jsontr,type(jsontr))  # ["hello word", {"a": "b"}] <class 'str'>
# 使用open函数
with open('data_test.txt',mode='w',encoding='utf8') as f:
    # 使用write写入
    f.write(jsontr)

["hello word", {"a": "b"}] <class 'str'>

进程已结束,退出代码为 0

运行成功后查看:

解析为Python格式

json.loads()

复制代码
# 导包
import json
# 使用json.loads方法将 字符串 转化为 python 列表
jsonls = json.loads('["a","b","c",{"a":1,"b":2},{"a":2,"b":3},{"ab":"cd"}]')
# 打印
print(jsonls,type(jsonls))

['a', 'b', 'c', {'a': 1, 'b': 2}, {'a': 2, 'b': 3}, {'ab': 'cd'}] <class 'list'>

进程已结束,退出代码为 0
json文件操作
写入json文件

示例:

复制代码
# 导包
import json
# 写一个字典test_data
test_data = {
    "id":1,
    "test_name":[
        "1,打开浏览器"
        "2,输入账号密码"
    ]
}
# 使用open函数--打开一个文件、权限 w、编码格式
with open('json_test.json', 'w',encoding='utf8') as f:
    # 存储文件--json.dump方法--文件体、文件流
    json.dump(test_data,f)

运行成功后查看:

json编码格式问题

复制代码
# 导包
import json
# 写一个字典test_data
test_data = {
    "id":1,
    "test_name":[
        "1-打开浏览器;"
        "2-输入账号密码;"
    ]
}
# 使用open函数--打开一个文件、权限 w、编码格式
with open('json_test.json', 'w',encoding='utf8') as f:
    # 存储文件--json.dump方法--文件体、文件流
    json.dump(test_data,f,ensure_ascii=False)

运行成功后查看:

读取json文件

示例:

复制代码
# 导包
import json
# 使用open函数--打开一个文件、编码格式
with open('json_test.json',encoding='utf8') as f:
    # 加载文件--json.load方法--文件流
    datajs = json.load(f)
    # 打印并查看类型
    print(datajs, type(datajs))

ps:需要先写入内容,若json文件为空,则报错

复制代码
{'id': 1, 'test_name': ['1,打开浏览器2,输入账号密码']} <class 'dict'>

进程已结束,退出代码为 0

未完待续。。。

相关推荐
别慌,让我先缓缓8 小时前
PyModbus 从入门到精通教程
python
景彡先生8 小时前
Python Flask详解:从入门到实战,轻量级Web框架的魅力
前端·python·flask
敲代码的嘎仔8 小时前
数据结构算法学习day3——二分查找
java·开发语言·数据结构·学习·程序人生·算法·职场和发展
大白的编程日记.8 小时前
【Linux学习笔记】线程安全问题之单例模式和死锁
linux·笔记·学习
安冬的码畜日常8 小时前
【JUnit实战3_23】 第十四章:JUnit 5 扩展模型(Extension API)实战(上)
测试工具·junit·单元测试·jdbc·h2·extension模型·junit5扩展
JJJJ_iii8 小时前
【机器学习12】无监督学习:K-均值聚类与异常检测
人工智能·笔记·python·学习·机器学习·均值算法·聚类
Tony Bai9 小时前
从 Python 到 Go:我们失去了什么,又得到了什么?
开发语言·后端·python·golang
qq_571099359 小时前
学习周报二十
学习
wudl55669 小时前
python字符串处理与正则表达式--之八
开发语言·python·正则表达式