自动化框架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相当于改名卡,使用后原来的名字就不能用了
相关推荐
SelectDB20 小时前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode2 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智6 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_6 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉6 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造