自动化框架pytest

1.简介

pytest是一个基于Python的测试框架,广泛用于编写简单且可扩展的测试代码。它支持单元测试、功能测试和集成测试,适用于从简单脚本到复杂应用程序的测试场景。

2.安装

复制代码
pip install pytest==8.3.2

|-----------|--------------|
| pytest 版本 | 最低 Python 版本 |
| 8.0+ | 3.8+ |
| 7.1+ | 3.7+ |
| 6.2 - 7.0 | 3.6+ |
| 5.0 - 6.1 | 3.5+ |
| 3.3 - 4.6 | 2.7, 3.4+ |

注意自己的python版本是否支持要下载的pytest版本

3.用例运行规则

安装完pytest后,在已test开头的方法前面会出现这个运行的图标

规则:

1. ⽂件名必须以 test_ 开头或者 _test 结尾

2. 测试类必须以 Test 开头,并且不能有 init ⽅法。

3. 测试⽅法必须以 test 开头

满足上述规则的用例,我们在终端输入pytest就会自动执行这些用例

**注意:**测试的Python类中不可以添加init⽅法

pytest 在实例化测试类时,默认会调用无参数的构造函数。如果测试类中定义了 __init__ 方法,可能会导致 pytest 无法正确初始化测试类,从而引发错误。

测试类的主要目的是定义测试方法,而不是管理复杂的初始化逻辑。pytest 提供了其他机制(如 fixture)来处理初始化需求。

4.前后置

使用 setup_methodsetup_class 方法来替代 __init__ 方法。这些方法是 pytest 推荐的初始化方式,会在测试运行前自动调用。

pytest 框架提供三种⽅法做前后置的操作:

setup_method 和 teardown_method:这两个⽅法⽤于类中的每个测试⽅法的前置和后置操

作。

setup_class 和 teardown_class :这两个⽅法⽤于整个测试类的前置和后置操作。

fixture:这是 pytest 推荐的⽅式来实现测试⽤例的前置和后置操作。 fixture 提供了更

灵活的控制和更强⼤的功能。(fixture将在后面单独讲解)

setup_method 和 teardown_method 会在每个方法执行前后都执行一遍

setup_class 和 teardown_class 会在本类的所有测试方法执行前执行一次,执行后执行一次,但是不能跨测试类执行(fixture能够解决这个问题)

5.pytest命令参数

基础运行参数

  • -v--verbose: 显示详细测试结果,包括每个测试用例的名称和状态。
  • -q--quiet: 简化输出,仅显示总体结果。
  • -k <表达式>: 通过关键字表达式筛选测试用例。例如 pytest -k "test_login" 仅运行名称包含 test_login 的测试。
  • -m <标记>: 运行带有特定标记的测试用例。例如 pytest -m smoke 仅运行标记为 smoke 的测试。

测试范围控制

  • :: 指定特定测试类或方法。例如 pytest tests/test_module.py::TestClass::test_method 仅运行指定方法。
  • --collect-only: 仅列出可用的测试用例但不执行。
  • --lf--last-failed: 仅重新运行上次失败的测试。
  • --ff--failed-first: 先运行上次失败的测试,再运行其他测试。

输出与报告

  • --tb=<style>: 设置错误回溯格式。可选值:auto(默认)、longshortnolinenative
  • -r <chars>: 显示额外摘要信息。例如 -rA 显示所有结果,-rE 显示错误。
  • --junitxml=<path>: 生成 JUnit 格式的 XML 报告。
  • --html=<path>: 生成 HTML 报告(需安装 pytest-html 插件)。

调试与诊断

  • -s: 禁用捕获,直接输出打印内容(相当于 --capture=no)。
  • --pdb: 在测试失败时自动进入调试模式。
  • --setup-show: 显示测试的 fixture 执行过程。
  • --durations=<N>: 显示最慢的 N 个测试用例的执行时间。

其他实用参数

  • -x: 遇到第一个失败时立即停止测试。
  • --maxfail=<num>: 允许的最大失败次数,达到后停止测试。
  • --cov=<path>: 生成代码覆盖率报告(需安装 pytest-cov 插件)。
  • -n <num>: 使用多进程并行运行测试(需安装 pytest-xdist 插件)。

6.pytest配置文件

在当前项⽬下创建 pytest.ini ⽂件,pytest.ini作用于同级目录及其子目录,该⽂件为 pytest 的配置⽂件,以下为常⻅的配置选项:

|------------------|--------------------------|
| 参数 | 解释 |
| addopts | 指定在命令⾏中默认包含的选项。 |
| testpaths | 指定搜索测试的⽬录。 |
| python_files | 指定发现测试模块时使⽤的⽂件匹配模式。 |
| python_classes | 指定发现测试类时使⽤的类名前缀或模式。 |
| python_functions | 指定发现测试函数和⽅法时使⽤的函数名前缀或模式。 |
| norecursedirs | 指定在搜索测试时应该避免递归进⼊的⽬录模式。 |
| markers | 定义测试标记,⽤于标记测试⽤例。 |

复制代码
[pytest]
addopts = -vs
testpaths = ./cases
python_files = test_*.py
python_classes = Test*

7.断言

断⾔( assert )是⼀种调试辅助⼯具,⽤于检查程序的状态是否符合预期。如果断⾔失败(即条件为假),Python解释器将抛出⼀个 AssertionError 异常。断⾔通常⽤于检测程序中的逻辑错误。pytest 允许你在 Python 测试中使⽤标准的 Python assert语句来验证预期和值。

语法:

复制代码
assert 条件,错误信息

• 条件 :必须是⼀个布尔表达式。
• 错误信息 :当条件为假时显⽰的错误信息,可选。

8.参数化

参数化设计是⾃动化设计中的⼀个重要组成部分,它通过定义设计参数和规则,使得设计过程更加灵活和可控。

pytest中内置的 pytest.mark.parametrize 装饰器允许对测试函数的参数进⾏参数化。

在用例上使用参数化

在类上使用参数化:

复制代码
@pytest.mark.parametrize("test_input,expected",[("3+2",5),("22*2",44),("3-2",1),("5/2",2.5)])
class Test_01:
    def test_01(self,test_input,expected):
        assert eval(test_input) == expected

    def test_02(self,test_input,expected):
        assert eval(test_input) == expected

    def test_03(self,test_input,expected):
        assert eval(test_input) == expected

对模块中所有测试进行参数化

复制代码
import pytest

pytestmark = pytest.mark.parametrize("test_input,expected",[("3+2",5),("22*2",44),("3-2",1),("5/2",2.5)])
class Test_01:
    def test_01(self,test_input,expected):
        assert eval(test_input) == expected

    def test_02(self,test_input,expected):
        assert eval(test_input) == expected

    def test_03(self,test_input,expected):
        assert eval(test_input) == expected

class Test_02:
    def test_04(self,test_input,expected):
        assert eval(test_input) == expected

    def test_05(self,test_input,expected):
        assert eval(test_input) == expected

    def test_06(self,test_input,expected):
        assert eval(test_input) == expected

9.fixture

概念:

Fixture 是测试框架中的一个重要概念,用于在测试运行前准备所需的数据或环境,并在测试完成后进行清理。Fixture 可以确保测试在一致和可控的条件下运行,提高测试的可靠性和可维护性。

主要作用:

Fixture 通常用于以下几种场景:

  • 数据库初始化:例如创建测试表、插入测试数据。
  • 文件系统准备:例如创建临时文件或目录。
  • 网络请求模拟:例如模拟 API 返回数据。
  • 资源管理:例如打开和关闭数据库连接。

fixture基本使用一:

复制代码
def fixture_01():
    print("fixture_01")
def test_fixture_01():
    fixture_01()
    print("test_fixture_01")



@pytest.fixture
def fixture_02():
    print("fixture_02")
def test_fixture_02(fixture_02):
    print("test_fixture_02")

未标记 fixture ⽅法的调⽤与 fixture 标记的⽅法调⽤完全不⼀样,前者需要在⽅法体中调⽤,

⽽后者可以将函数名作为参数进⾏调⽤。

测试脚本中存在的很多重复的代码、公共的数据对象时,使⽤ fixture 最为合适

fixture基本使用二:

访问列表⻚和详情⻚之前都需要执⾏登录操作,相当于前置

复制代码
import pytest
@pytest.fixture
def login():
    print("---执⾏登陆操作-----")
def test_list(login):
    print("---访问列表⻚")
def test_detail(login):
    print("---访问详情⻚")

fixture嵌套:

复制代码
import pytest
@pytest.fixture
def first_entry():
    return "first"

@pytest.fixture
def second_entry(first_entry):
    return [first_entry]

def test_01(second_entry):
    second_entry.append("second_entry")
    print(second_entry)

测试不必局限于单个 fixture ,它们可以依赖于您想要的任意数量的 fixture ,并且fixture 也可以使⽤其他 fixture 。 pytest 最伟⼤的优势之⼀是其极其灵活的 fixture 系统,它允许我们将测试的复杂需求简化为更简单和有组织的函数,我们只需要每个函数描述它们所依赖的事物

请求多个fixture

  • fixture 的执行顺序由 pytest 自动管理,通常按依赖关系和定义顺序执行。

yield fixture:

在 pytest 中,yield fixture 是一种通过生成器(yield)机制管理资源的 fixture。它允许在测试执行前进行初始化操作,并在测试完成后自动执行清理操作,适合处理需要释放的资源(如数据库连接、文件句柄等)。

yield相当于return ,但又不太一样,在测试用例执行完毕后,会回来执行yield下面的代码

创建⽂件句柄与关闭⽂件:

复制代码
import pytest
@pytest.fixture
def file_read():
    print("打开⽂件句柄")
    fo = open("test.txt", "r")
    yield fo
    print("关闭打开的⽂件")
    fo.close()

def file_write():
    print("打开⽂件句柄")
    fo = open("test.txt","w",encoding="utf-8")
    return fo

def test_file(file_write, file_read):
# 写⼊数据
    w = file_write
    w.write("测试数据")
    w.close() # 写⼊后关闭⽂件句柄,以便读取
# 读取数据
    r = file_read
    str = r.read(10)
    print("⽂件内容:", str)

带参数的fixture:

参数详解:
• scope 参数⽤于控制fixture的作⽤范围,决定了fixture的⽣命周期。可选值有:
◦ function (默认):每个测试函数都会调⽤⼀次fixture。
◦ class :在同⼀个测试类中共享这个fixture。
◦ module :在同⼀个测试模块中共享这个fixture。(⼀个⽂件⾥)
◦ session :整个测试会话中共享这个fixture。

• autouse 参数默认为 False 。如果设置为 True ,则每个测试函数都会⾃动调⽤该fixture,
⽆需显式传⼊

• params 参数⽤于参数化fixture,⽀持列表传⼊。每个参数值都会使fixture执⾏⼀次,类似于for循环

• ids 参数与 params 配合使⽤,为每个参数化实例指定可读的标识符(给参数取名字)

• name 参数⽤于为fixture显式设置⼀个名称。如果使⽤了 name ,则在测试函数中需要使⽤这个名称来引⽤ fixture (给fixture取名字)

1.scope

scope="function"

每个测试用例运行前都会调用

fixture默认是funtions,每个方法
scope="class"

在同⼀个测试类中共享这个fixture。

复制代码
scope="session"
  • 作用域 :fixture 在整个模块(即一个 .py 文件)中只执行一次。

  • 用途:适合在模块级别进行初始化和清理操作,例如打开数据库连接、设置全局配置等。

    #conftest.py

    import pytest
    @pytest.fixture(scope="module")
    def module_fixture():
    print("\n模块级别的前置操作")
    yield
    print("\n模块级别的后置操作")

    #作用于整个test_module.py

    def test_module1(module_fixture):
    print("test_module1")

    def test_module2(module_fixture):
    print("test_module2")

scope="session"

  • 作用域:fixture 在整个测试会话(即所有测试文件)中只执行一次。
  • 用途:适合在会话级别进行初始化和清理操作,例如启动浏览器、连接数据库等。
复制代码
  #conftest.py

  import pytest
  @pytest.fixture(scope="session")
  def module_fixture():
      print("\n模块级别的前置操作")
      yield
      print("\n模块级别的后置操作")

  #test_module1.py

  def test_module1(module_fixture):
      print("test_module11")


  def test_module2(module_fixture):
      print("test_module12")

  #test_module2.py


  def test_module1(module_fixture):
      print("test_module21")


  def test_module2(module_fixture):
      print("test_module22")

2.autose

autouse 默认为 False ,即当前的 fixture 需要⼿动显⽰调⽤,在该案例之前我们默认使⽤的

都是 autouse=False

当 autouse=True 时, fixture 会在所有测试函数执⾏之前⾃动调⽤,⽆论这些测试函数是否显式地引⽤了该 fixture

3.params

  • 作用 :用于参数化 fixture,支持传入一个列表。每个参数值都会使 fixture 执行一次,类似于 for 循环。

  • 用途:适合在不同参数下重复执行同一个 fixture。

    import pytest

    定义⼀个参数化的 fixture

    @pytest.fixture(params=["a", "b"])
    def data_provider(request):
    return request.param

    定义⼀个测试函数,它依赖于上⾯的参数化 fixture

    def test_data(data_provider):
    assert data_provider != None
    print(f"Testing with data provider: {data_provider}")

4.ids

  • 作用 :与 params 配合使用,为每个参数化实例指定可读的标识符(给参数取名字)。
  • 用途:提高测试结果的可读性,特别是在参数较多时。就是告诉我们用的是那个参数,给参数取的名字

5.name

  • 作用 :用于为 fixture 显式设置一个名称。如果使用了 name,则在测试函数中需要使用这个名称来引用 fixture。
  • 用途:避免 fixture 名称与测试函数中的变量名冲突,或者为 fixture 取一个更具描述性的名称。
  • name相当于改名卡,使用后原来的名字就不能用了
相关推荐
心一信息2 小时前
如何在Ubuntu上部署excalidraw
linux·运维·ubuntu
人生匆匆2 小时前
linux ext4缩容home,扩容根目录
linux·运维·服务器
冗量2 小时前
PPT自动化 python-pptx - 8: 文本(text)
python·自动化·powerpoint
海岸线科技2 小时前
汽车供应链PPAP自动化审核指南:如何用AI实现规则精准匹配与文件智能校验
人工智能·自动化·汽车
IT成长日记2 小时前
【自动化运维神器Ansible】YAML支持的数据类型详解:构建高效Playbook的基石
运维·自动化·ansible·数据类型·yaml·playbook
IT成长日记2 小时前
【自动化运维神器Ansible】YAML语法详解:Ansible Playbook的基石
运维·自动化·ansible·yaml
demaichuandong2 小时前
丝杆升降机在物流运输领域有哪些应用场景
人工智能·自动化·信号处理
yuanzhengme3 小时前
Shell【脚本 02】离线安装配置Zookeeper及Kafka并添加service服务和开机启动(脚本分析)
linux·zookeeper·kafka·自动化·安装脚本
sakoba3 小时前
Docker学习其二(容器卷,Docker网络,Compose)
运维·网络·学习·docker·容器·基础