Skip to content

15Panda:拒绝低效,数据驱动新手段

你好,我是蔡超,欢迎来到第 15 课时,经过从第一节课迄今为止的学习,你已经对测试框架的搭建,使用有比较深入的理解。 公司里的各种项目假设需要自动化测试,你也可以根据本专栏能融合 API 测试和 UI 测试,并学会了使用 PageObject 模型,且拥有数据驱动能力的测试框架了。

今天我将带你在数据驱动这个话题上继续深耕 ,一起来探索在自动化测试中如何使用不同类型的数据驱动,下方这个本课时的内容脑图可供你学习参考。

使用 pytest 进行数据驱动的基本思路

我们知道 pytest 可以通过 pytest.mark.parametrize 来实现数据驱动,而 pytest.mark.parametrize 接受的数据格式要求为:

  • 如果只有一组数据,以列表的形式存在;

  • 如果有多组数据,以列表嵌套元组的形式存在(例如 [0,1] 或者 [(0,1), (1,2)])。

既然如此,我们只需要创建一个方法,在这个方法里解析我们提供的各种数据格式,然后解析后返回 pytest.mark.parametrize 支持的格式就好。

常规的数据驱动方法

1.pytest 操作 JSON/YAML 文件实现数据驱动

在《13 | DDT:博采众长,数据驱动的秘诀(一)》中我们讲到了在 unittest 框架中操作 JSON 和 YAML 文件实现数据驱动。

那么在 pytest 中,又该如何实现呢?

我们先按照刚刚所说的使用 pytest 进行数据驱动的基本思路创建一个读取 JSON 文件和 YAML 文件的方法:

python
def read_data_from_json_yaml(data_file):
    return_value = []
    data_file_path = os.path.abspath(data_file)
    print(data_file_path)
    _is_yaml_file = data_file_path.endswith((".yml", ".yaml"))
    with codecs.open(data_file_path, 'r', 'utf-8') as f:
        # Load the data from YAML or JSON
        if _is_yaml_file:
            data = yaml.safe_load(f)
        else:
            data = json.load(f)
    for i, elem in enumerate(data):
        if isinstance(data, dict):
            key, value = elem, data[elem]
            if isinstance(value, dict):
                case_data = []
                for v in value.values():
                    case_data.append(v)
                return_value.append(tuple(case_data))
            else:
                return_value.append((value,))
    return return_value

read_data_from_json_yaml 这个方法,实现了自动读取 JSON 文件和 YAML 文件,并且把 JSON 文件和 YAML 文件中的数据提取出来,并按照 pytest.mark.parametrize 可接收的方式返回。代码比较简单,我就不再一一讲解其含义

注意:如果你的测试文件与本文中的 YAML 和 JSON 文件的层次不同,此方法也需要做相应的修正。

有了这个方法,JSON 或者 YAML 文件的数据通过此方法就可以转换成 pytest.mark.parametrize 认可的格式直接传入了。

下面实践一下,在 lagouAPITest 项目根目录下创建如下文件目录:

java
|--lagouAPITest
    |--tests_pytest_ddt
        |--test_baidu_ddt.py
        |--test_baidu_ddt.json
        |--test_baidu_ddt.yaml
        |--test_baidu_ddt.xlsx
        |--__init__.py
        |--conftest.py

其中,test_baidu_ddt.json 文件的内容如下:

python
{ 
  "case1": {
  "search_string": "itesting",
  "expect_string": "iTesting"
  },
  "case2": {
  "search_string": "helloqa.com",
  "expect_string": "iTesting"
  }
}

test_baidu_ddt.yaml 文件的内容如下:

python
"case1":
  "search_string": "itesting"
  "expect_string": "iTesting"
 
"case2": 
  "search_string": "helloqa.com"
  "expect_string": "iTesting"

test_baidu_ddt.py 文件的代码如下:

python
# -*- coding: utf-8 -*-
import codecs
import json
import os
import time
import pytest
import yaml

def read_data_from_json_yaml(data_file):
    return_value = []
    data_file_path = os.path.abspath(data_file)
    print(data_file_path)
    _is_yaml_file = data_file_path.endswith((".yml", ".yaml"))
    with codecs.open(data_file_path, 'r', 'utf-8') as f:
        # Load the data from YAML or JSON
        if _is_yaml_file:
            data = yaml.safe_load(f)
        else:
            data = json.load(f)
    for i, elem in enumerate(data):
        if isinstance(data, dict):
            key, value = elem, data[elem]
            if isinstance(value, dict):
                case_data = []
                for v in value.values():
                    case_data.append(v)
                return_value.append(tuple(case_data))
            else:
                return_value.append((value,))
    return return_value

@pytest.mark.baidu
class TestBaidu:
    @pytest.mark.parametrize('search_string, expect_string',  read_data_from_json_yaml('tests_pytest_ddt/test_baidu_ddt.yaml'))
    def test_baidu_search(self, login, search_string, expect_string):
        driver, s, base_url = login
        driver.get(base_url + "/")
        driver.find_element_by_id("kw").send_keys(search_string)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
        print(search_results)
        assert (expect_string in search_results) is True

if __name__ == "__main__":
    pytest.main(['-s', '-v'])

此段代码跟我们在《14 | DDT:博采众长,数据驱动的秘诀(二)》中讲解的代码几乎相同,唯一的改变在于增加了一个新方法 read_data_from_json_yaml,另外 @pytest.mark.parametrize 的参数,从直接提供参数变成了从文件提供参数。

java
read_data_from_json_yaml('tests_pytest_ddt/test_baidu_ddt.yaml'))

在命令行中通过如下方式运行:

python
D:\_Automation\lagouAPITest>pytest tests_pytest_ddt -s -v

运行结束后查看结果如下:

可以看到,两个测试用例都执行了,并且 YAML 文件中的数据被正确读取。

那么如果我们现在要执行 JSON 文件中的数据该如何操作呢?把上述第 40 行代码中的 yaml 文件后缀换成 json 文件后缀,再次执行即可。

2.pytest 操作 Excel 文件实现数据驱动

在实际应用中,也有很多公司使用 Excel 来做数据驱动。 在 python 中,读写 Excel 的 library 很多,常见的有 xlrd、xlwt,以及openpyxl。由于 xlrd 和 xlwt 只能分别用作读和写,实现同样的读写操作,它的代码行数较多,故逐渐变得不再流行。所以下面我将重点介绍 openpyxl 的使用。

(1)openpyxl 安装

python
pip install openpyxl

(2)openpyxl 使用

python
   from openpyxl import load_workbook, Workbook
if __name__ == "__main__":
    # 创建一个workbook
    file_name = r'c:\test.xlsx'
    wb = Workbook()
    # 创建一个sheet,名为iTesting,把它插入到最前的位置
    wb.create_sheet('iTesting',0)
    # 创建一个sheet,名为VIPTEST,把它插入index为1的位置
    wb.create_sheet('VIPTEST',1)
    # 保存表格
    wb.save(file_name)
    # 读和写
    # 初始化表格
    wb2 = load_workbook(file_name)
    # 读,获取所有的sheet名称
    print(wb2.sheetnames)

    # 获取sheet名为iTesting的表格
    s = wb2['iTesting']
    # 将A1行的值设置为iTesting
    s['A1'] = 'iTesting'
    # 将第2行,第一列的值设置为1
    s.cell(row=2, column=1).value = 1
    # 打印第2行第一列单元格的值 --方法1
    print(s.cell(row=2,column=1).value)
    # 打印第2行第一列单元格的值 --方法2
    print(s['A2'].value)
    # 保存表格
    wb.save(file_name)

上面的一段代码里,我简单介绍了 openpyxl 的用法,涉及创建表格、创建 sheet 名、读取单元格的值、设置单元格的值等部分。你可以看出使用 openpyxl 操作 excel 是相对比较简单的。
(3)openpyxl 结合 pytest 实现数据驱动

文件 test_baidu_ddt.xlsx 的内容如下(sheet 名 iTesting):

我们来写个读 Excel 的方法,代码如下:

python
def read_data_from_excel(excel_file, sheet_name):
    return_value = []
    # 判断文件是否存在
    if not os.path.exists(excel_file):
        raise ValueError("File not exists")
    # 打开指定的sheet
    wb = load_workbook(excel_file)
    # 按照pytest接受的格式输出数据
    for s in wb.sheetnames:
        if s == sheet_name:
            sheet = wb[sheet_name]
            for row in sheet.rows:
                return_value.append([col.value for col in row])
    # 第一行数据是标题,故skip掉
    return return_value[1:]

更新 test_baidu_ddt.py 文件,把 read_data_from_excel 的方法加进去,更新后的代码如下:

python
# -*- coding: utf-8 -*-
import codecs
import json
import os
import time
import pytest
import yaml
from openpyxl import load_workbook

def read_data_from_json_yaml(data_file):
    return_value = []
    data_file_path = os.path.abspath(data_file)
    print(data_file_path)
    _is_yaml_file = data_file_path.endswith((".yml", ".yaml"))
    with codecs.open(data_file_path, 'r', 'utf-8') as f:
        # Load the data from YAML or JSON
        if _is_yaml_file:
            data = yaml.safe_load(f)
        else:
            data = json.load(f)
    for i, elem in enumerate(data):
        if isinstance(data, dict):
            key, value = elem, data[elem]
            if isinstance(value, dict):
                case_data = []
                for v in value.values():
                    case_data.append(v)
                return_value.append(tuple(case_data))
            else:
                return_value.append((value,))
    return return_value

def read_data_from_excel(excel_file, sheet_name):
    return_value = []
    if not os.path.exists(excel_file):
        raise ValueError("File not exists")
    wb = load_workbook(excel_file)
    for s in wb.sheetnames:
        if s == sheet_name:
            sheet = wb[sheet_name]
            for row in sheet.rows:
                return_value.append([col.value for col in row])
    print(return_value)
    return return_value[1:]

@pytest.mark.baidu
class TestBaidu:
    # 注意,此处调用我换成了读Excel的方法
    @pytest.mark.parametrize('search_string, expect_string',  read_data_from_excel(r'D:\_Automation\lagouAPITest\tests_pytest_ddt\test_baidu_ddt.xlsx', 'iTesting'))
    def test_baidu_search(self, login, search_string, expect_string):
        driver, s, base_url = login
        driver.get(base_url + "/")
        driver.find_element_by_id("kw").send_keys(search_string)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
        print(search_results)
        assert (expect_string in search_results) is True

if __name__ == "__main__":
    pytest.main(['-s''-v''tests_pytest_ddt'])

在命令行中通过如下方式再次运行即可:

python
D:\_Automation\lagouAPITest>pytest tests_pytest_ddt -s -v

运行后查看结果,你会发现测试被正确执行,测试数据是从 Excel 指定的 sheet 名中获取的。

数据驱动新姿势

1.Pandas 实现数据驱动

openpyxl 操作 Excel 非常简洁,但是相对于 Pandas 来说,还不够简洁,而且 openpyxl 运算效率不如 Pandas,特别是当表格行项目过多时,openpyxl 运算较慢。

我们知道,当测试脚本过多时,单个脚本的运行时间差异加起来也会是个不小的浪费。作为测试开发,我们有义务提升测试效率。

Pandas 是一个强大的分析结构化数据的工具集,它的使用基础是 Numpy(提供高性能的矩阵运算);Pandas 用于数据挖掘和数据分析,同时也提供数据清洗功能。使用 Pandas 操作 Excel 数据,就好像数数那样简单。

Pandas 安装

java
# pandas默认依赖xlrd库,故先安装xlrd
pip install xlrd
# 安装Pandas
pip install Pandas

Pandas 语法

python
import Pandas as pd
# 首先初始化,engine默认是xlrd
s = pd.ExcelFile(path_or_buffer, engine=None)

# 接着parse
s.parse(sheet_name=0,header=0,names=None,index_col=None,usecols=None,
squeeze=False,converters=None,true_values=None,false_values=None,
skiprows=None,nrows=None,na_values=None,parse_dates=False,
date_parser=None,thousands=None,comment=None,skipfooter=0,
convert_float=True,mangle_dupe_cols=True,**kwds,)

Pandas 读取 Excel 文件非常简单,首先使用 Pandas 初始化 ExcelFile。其两个参数path_or_buffer 是我们要读取的文件路径。

Excel 文件名称建议使用英文路径及英文命名方式,尽量不要使用中文。

java
import pandas as pd
path_or_buffer = r'D:\_Automation\lagouAPITest\tests_pytest_ddt\test_baidu_ddt.xlsx'

engine 是供 Pandas 使用的 engine,可选项为"xlrd""openpyxl""odf"和"pyxlsb",如果不提供,默认使用 xlrd。

parse 函数的参数

初始化后,可以使用 s.parse() 函数。parse 函数有非常多的参数,在此我列出常用的几个。

  • sheet_name: Excel 的 sheet 名

sheet_name 可以是整型数字、列表名,或者上述两者组合。

python
# 通过整型数字读取。读取第一个sheet。 Pandas sheet名下标以0开始
s = pd.ExcelFile(path_or_buffer, sheet_name = 0)
# 通过列表名读取
data = s.parse(sheet_name = 'iTesting')
# 通过index读取。读取第一个sheet
data = s.parse(sheet_name = 0)
#组合读取。读取第4个sheet,名为iTesting的sheet以及第7个sheet
data = s.parse(sheet_name = [3, 'iTesting', 'Sheet6'])
  • header:使用哪一行作为列名

header 默认值为 0,即第一行,也可以设置为 [0, x]。

(例如 [0,1] 意味着将前两行作为多重索引)

python
data = s.parse(sheet_name = 'iTesting', header = 0)

需要注意: Pandas 默认使用第一行为 header,所以在 Excel 里,第一行必须是 title,如果第一行是数据,将会导致第一行数据被遗漏。如果不想要 header,可以参数传递 header=None。

  • usecols:待读取的列

usecols 接收整型,从 0 开始,例如 [0, 1, 2],也可以使用列名例如 "A:D, F",表示读取 A 到 D 列,以及 F 列。

python
data = s.parse(sheet_name = 'iTesting', usecols='A:D')
  • skiprows:读取时,跳过特定行

skiprows=n,跳过前 n 行;skiprows = [a, b, c],跳过第 a+1、b+1、c+1 行(索引从0开始)

python
data = s.parse(sheet_name = 'iTesting', skiprows = [1,2,3])
  • nrows:需要读取的行数

仅仅列出要读取的行数

python
data = s.parse(sheet_name = 'iTesting', nrows = 3)

Pandas 结合 pytest 实现数据驱动

了解了 Pandas 语法后,我们来看下如何使用 Pandas 读取 Excel 数据:

python
def read_data_from_pandas(excel_file, sheet_name):
    if not os.path.exists(excel_file):
        raise ValueError("File not exists")
    # 初始化
    s = pd.ExcelFile(excel_file)
    # 解析Excel Sheet
    df = s.parse(sheet_name)
    # 以list格式返回数据
    return df.values.tolist()

可以看到,使用 pandas 读取 Excel 数据更加简洁方便。

最后,我们来更新下 test_baidu_ddt.py 文件,更新后的代码如下:

python
# -*- coding: utf-8 -*-
import codecs
import json
import os
import time
import pytest
import yaml
from openpyxl import load_workbook
import pandas as pd
# 读取Yaml文件和Json文件
def read_data_from_json_yaml(data_file):
    return_value = []
    data_file_path = os.path.abspath(data_file)
    print(data_file_path)
    _is_yaml_file = data_file_path.endswith((".yml", ".yaml"))
    with codecs.open(data_file_path, 'r', 'utf-8') as f:
        # Load the data from YAML or JSON
        if _is_yaml_file:
            data = yaml.safe_load(f)
        else:
            data = json.load(f)
    for i, elem in enumerate(data):
        if isinstance(data, dict):
            key, value = elem, data[elem]
            if isinstance(value, dict):
                case_data = []
                for v in value.values():
                    case_data.append(v)
                return_value.append(tuple(case_data))
            else:
                return_value.append((value,))
    return return_value
# 读取Excel 文件 -- openpyxl
def read_data_from_excel(excel_file, sheet_name):
    return_value = []
    if not os.path.exists(excel_file):
        raise ValueError("File not exists")
    wb = load_workbook(excel_file)
    for s in wb.sheetnames:
        if s == sheet_name:
            sheet = wb[sheet_name]
            for row in sheet.rows:
                return_value.append([col.value for col in row])
    print(return_value)
    return return_value[1:]
# 读取Excel文件 -- Pandas
def read_data_from_pandas(excel_file, sheet_name):
    if not os.path.exists(excel_file):
        raise ValueError("File not exists")
    s = pd.ExcelFile(excel_file)
    df = s.parse(sheet_name)
    return df.values.tolist()
@pytest.mark.baidu
class TestBaidu:
    @pytest.mark.parametrize('search_string, expect_string',  read_data_from_pandas(r'D:\_Automation\lagouAPITest\tests_pytest_ddt\test_baidu_ddt.xlsx', 'iTesting'))
    def test_baidu_search(self, login, search_string, expect_string):
        driver, s, base_url = login
        driver.get(base_url + "/")
        driver.find_element_by_id("kw").send_keys(search_string)
        driver.find_element_by_id("su").click()
        time.sleep(2)
        search_results = driver.find_element_by_xpath('//*[@id="1"]/h3/a').get_attribute('innerHTML')
        print(search_results)
        assert (expect_string in search_results) is True

if __name__ == "__main__":
    pytest.main(['-s', '-v', 'tests_pytest_ddt'])

在命令行中通过如下方式再次运行即可:

js
D:\_Automation\lagouAPITest>pytest tests_pytest_ddt -s -v

运行后查看结果,你会发现测试被正确执行,测试数据是通过 Pandas 从 Excel 指定的 sheet 名中获取的。

事实在,Pandas 不仅仅能读取 Excel 文件,还可以读取 HTML 文件、TXT 文件、JSON 文件、数据库文件 (.sql) 等。在数据分析领域,Pandas 使用非常广泛,更多具体的 Pandas 使用,请自行查阅。

2.自定义实现数据驱动

我在第 11、12 课时的" DDT:博采众长,数据驱动的秘诀"里,详细讲解了如何使用 ddt、pytest.mark.parametrize 和 pytest.fixture 来实现数据驱动。今天我来讲 pytest 里另外一个实现数据驱动的方式 pytest_generate_tests。

  • 直接提供数据实现数据驱动

pytest 中提供了一个钩子函数,名为 pytest_generate_tests。此函数在 pytest 收集测试函数时会被调用。通过传入 metafunc 对象,我们可以"自定义"数据驱动,即通过调用metafunc.parametrize() 来进行参数化。

我们先看一个例子:

python
# 定义文件test_customize_ddt.py
import pytest

def pytest_generate_tests(metafunc):
    # 查看metafunc有多少种可用方法
    print(dir(metafunc))
    if "text_para" in metafunc.fixturenames:
        # 指定参数化名称,及其对应的值
        metafunc.parametrize("text_para", [["iTesting", "iTesting"], ["always", "always"], ["awesome", "good"]])

class TestClass:
    def test_func(self, text_para):
        input_str, output_str = text_para
        print(input_str)
        print(output_str)
        assert input_str == output_str

if __name__ == "__main__":
    pytest.main(['-s', '-v', 'test_pytest_ddt/test_customize_ddt.py'])

直接在 Pycharm 中运行此文件,或者在命令行中通过如下方式运行:

html
D:\_Automation\lagouAPITest>pytest -s -v tests_pytest_ddt/test_customize_ddt.py

运行后查看结果:

可以看到,有 3 个测试用例被执行了,执行的测试用例是 test_func 这个函数,执行的结果是两个成功,一个失败(注意,一个用例失败不会影响其他用例执行)。其使用的数据正好就是我们提供的这组数据:

js
[["iTesting", "iTesting"], ["always", "always"], ["awesome", "good"]]

下面我来讲解下这段代码。

首先,我定义了一个函数,名字为 pytest_generate_tests(metafunc), 注意这个函数名称和参数名称均是固定的,不可更改。

然后,我在函数 pytest_generate_tests 中(第 7 行)打印出 metafunc 可用的方法有哪些。 事实上,通过查看源代码可以发现,metafunc 支持的属性有:

js
#: Access to the :class:`_pytest.config.Config` object for the test session.
# 用于在测试session中访问:class:`_pytest.config.Config`对象
metafunc.config
#: The module object where the test function is defined in.
#: 代表使用参数名称进行参数化的test function所在的模块对象
metafunc.module
#: Underlying Python test function.
#: 测试用例对象
metafunc.function
#: Set of fixture names required by the test function.
#: test function参数化所需的fixtures名字
metafunc.fixturenames
#: Class object where the test function is defined in or ``None``.
# test function所属的类的类对象如果没有就是None
metafunc.cls

我使用 metafunc.fixturenames 列出所有可能的 fixture 名字,并当它的名字跟我提供的 fixture 名称一样时,我使用 metafunc.parametrize 函数为其提供参数化的数据值,以便实现数据驱动(8~11 行)。

接着,我定义了一个测试类 TestClass,然后在其中定义了一个类方法 test_func,并在其中定义了一个"参数" text_para。 而这个"参数"名称 text_para 实际上就是我提供的 fixtures。

最后,pytest.main() 函数运行, 在收集测试函数时,会找到 test_func 这个函数,然后在运行这个函数前,函数 pytest_generate_tests 会被调用,通过查看代码运行,你可以看到:

metafunc 对象被传入进来,它的 5 个属性分别是:

接着 pytest 会在其中经过一系列复杂的操作,最终为 text_para 这个 fixture 完成参数化,并且根据数据的组数将测试用例 test_func 分成多个测试用例,接着依次运行新生成的测试用例,并且为每一个测试用例提供一组数据,如下:

接着,这些测试用例依次运行完毕,输出结果。

  • 从外部文件提供数据实现数据驱动

数据驱动的最大好处就是更改数据不需要更改代码, 所以将测试数据抽离出来到外部文件是通用的做法,下面我们就来看下如何做。

在 lagouAPITest 项目根目录下创建如下文件目录:

js
|--lagouAPITest
    |--tests_pytest_new_ddt
        |--test_new_ddt.py
        |--data_new_ddt.py
        |--__init__.py

其中 data_new_ddt.py 文件的内容如下:

python
tests = [
    ["iTesting", "iTesting"], 
    ["always", "always"], 
    ["awesome", "good"]
]

test_new_ddt.py 的代码如下:

python
import importlib
import pytest

def pytest_generate_tests(metafunc):
    package_name = metafunc.module.__package__
    for fixture in metafunc.fixturenames:
        if fixture.startswith('data_'):
            # 加载测试数据
            module_name = package_name + '.' + fixture
            tests = TestClass.load_tests(module_name)
            metafunc.parametrize(fixture, tests)

class TestClass:
    @staticmethod
    def load_tests(name):
        # 加载测试数据文件
        tests_module = importlib.import_module(name)
        # 针对每一个测试文件,赋予不同的测试值
        for test in tests_module.tests:
            yield test
    def test_func(self, data_new_ddt):
        input_str, output_str = data_new_ddt
        assert input_str == output_str

if __name__ == "__main__":
    pytest.main(args=['-s', '-v', 'tests_new_ddt/test_new_ddt.py'])

这段代码比较复杂,我来一一解释。

首先,函数 pytest_generate_tests 仍然是实现了把给定的 fixture(data_new_ddt)加载进来,并且根据测试数据生成多组测试用例。

其次, 测试类 TestClass 中的 load_tests 静态方法实现了解析测试数据并逐个返回, 这里用了yield。 yield 在fixture 里是个特殊的存在,它用于返回 fixture 的分组测试数据。正因为此,通过 load_tests 函数返回的数据才能正确地被 metafunc.parametrize 参数化(把 load_tests 里的 yield 改成 true,测试会出错)。

最后, 分组测试数据被生成的多组新测试用例返回,并用于测试方法 test_func 中,从而实现了从外部文件提供数据实现数据启动。

总结

本节课我们首先学习了数据驱动的新姿势 ------ Pandas。不同格式数据驱动的要点在于解析这些文件并将数据转换成 pytest.mark.parametrize 认可的数据格式。

至此,JSON、YAML、TXT、CSV、xlsx、sql 甚至 .py 格式的数据格式,对你来说就仅仅是写一个数据解析方法而已。

其次,本节课着重介绍了通过 pytest 的预留方法 pytest_generate_tests 来实现数据驱动。使用 pytest_generate_tests 实现数据驱动,可以允许你灵活地定制你的数据驱动模式。这部分代码稍微有点复杂,在了解其原理时,建议大家多读 pytest 源码,所谓书读千遍,其意自现。

课后作业

在本节课中,介绍数据驱动时,为了讲解简单,我实现数据驱动的 fixture 方法,都是直接放在测试文件中的,例如 read_data_from_excel、read_data_from_pandas 等。请尝试将他们放入 conftest.py 文件中 ,并更改你的代码使之能够正确运行。

好了,今天的课程就到这里,有任何问题也可以在下方讨论区留言,我是蔡超, 我们下节课再见。


关注公众号 iTesting,回复"测试框架",查看更多自研测试框架的技术原理。