快速上手pytest

news2025/7/21 11:41:17

1. pytest的基础

1.1 什么是pytest 

pytest 是 python 中的一个测试框架,用于编写简洁、可扩展的测试代码,帮助开发者验证结果是否与预期相符。

python 中有很多的测试框架,那我们为什么要学习 pytest 呢? 

pytest 的优势: 

  • 不需要复杂的类继承(不像 unittest)
  • 支持断言直接使用 python 的 assert 语句
  • 提供丰富的插件生态(如生成 HTML 报告、并行测试等) 

1.2 pytest的安装 

pytest 属于 python 的第三方库(不属于标准库),所有在使用之前需要在 terminal 中进行安装 

pip install pytest -i https://pypi.tuna.tsinghua.edu.cn/simple

 后面指定的是国内源下载,能够提高下载的速度

1.3 第一个测试例子 

创建一个文件:test_first.py 

python文件内容为: 

def add(num1, num2):
    return num1 + num2


def test_add():
    assert add(1, 2) == 3

运行代码:pytest test_first.py

2. pytest的核心功能 

2.1 测试发现规则 

pytest 会自动发现以下的文件: 

  • 文件名以 test_ 开头 或 _test结尾(如 test_first.py 或 first_test.py)
  • 类名以 Test 开头
  • 函数名以 test_开头 

文件名符合规则,是 pytest 处理文件的前提条件。类/函数符合规则,是执行具体测试的必要条件。 

若文件名符合规则,类符合规则,类中的函数不符合规则,则会跳过类中的不符合规则的函数。除非在符合规则的函数里面调用不符合规则的函数。 

符合规则的文件+类+不符合规则的函数  :

class TestAdd:
    def add(self):
        print(1 + 1)

运行结果:

符合规则的文件+类+函数:

class TestAdd:
    def test_add(self):
        print(1 + 1)

运行结果: 

2.2 运行测试的常用方式 

运行所有的测试:pytest

运行指定文件:pytest 文件名(符合规则) 

运行指定目录:pytest 目录/ 

运行包含关键字的测试:pytest -k "add"  #运行名称关于add的测试 

遇到错误时停止:pytest --pdb  #进入调试模式 

2.3 断言(assert) 

直接使用 python 的 assert 语句。 

断言的作用:判断实际结果是否与预期结果一致。

在 pytest 中运行测试时,控制台会通过特定符号直观反馈每个测试用例的执行结果。

以下是常见的符号及其含义: 

符号含义触发场景
.测试通过断言成功且无异常
F测试失败断言失败(如 assert 1 == 2)
E代码错误测试代码本身抛出异常(非断言失败)
s测试跳过使用 @pytest.mark.skip 主动跳过测试
x预期失败(XFAIL)测试标记为预期失败且确实失败
X意外通过(XPASS)测试标记为预期失败但实际通过了
w警告代码触发了警告(如弃用函数)

2.4 夹具(Fixture) 

2.4.1 夹具的作用与使用 

夹具的作用:为测试用例提供预置的环境和资源,避免重复写相同的准备代码,让测试更简洁、可维护。

  • 数据库连接
  • 临时文件
  • 模拟对象
  • 共享配置 

举个例子:假设你要测试“煮不同口味的面条” 

没有夹具:每次煮面都要自己拆包装、烧水、煮面、吃完洗碗......重复劳动。

有夹具:小助手自动帮你完成这些事:提前烧好一锅水(前置准备)、煮好面递给你(提供资源)、你吃完后,它自动洗碗(清理垃圾)。你只需要专注测试“面的味道”,其他杂活都交给它。

夹具的定义:用@pytest.fixture装饰器定义一个夹具 

写一个简单的代码(可能与实际业务不符),方便大家理解: 

@pytest.fixture
def user():
    return "Alice"

夹具的使用:在测试函数中将夹具作为参数传入即可使用 

def test_user(user):
    print(user)

运行结果: 

2.4.2 夹具的作用范围(scope) 

通过 scope 参数控制夹具的作用域: 

  • function(默认):每个测试函数执行一次 
  • class:每个测试类执行一次
  • module:每个 python 文件执行一次
  • session:整个 pytest 运行过程执行一次 

大家看到上面的夹具作用域,可能就有点懵了。可能不明白什么叫做执行一次,接下来就给大家深入解析一下: 

并不是说它们只能执行一次,而是说当设置不同的scope参数内容时,它们的作用域是不同的。 

作用域为function的代码理解: 

import pytest


class TestFruit:
    @pytest.fixture(scope="function")
    def ret_fruit(self):
        return {
            "A": "apple",
            "P": "pear",
            "W": "watermelon"
        }

    def test_fruit1(self, ret_fruit):
        ret_fruit["A"] = "avocado"
        print(ret_fruit)

    def test_fruit2(self, ret_fruit):
        print(ret_fruit)

 运行结果:

分析:

夹具作用域(scope="function"):

  • 规则:夹具 ret_fruit 在 每个测试函数执行前初始化一次,每个测试函数获得独立的字典对象。
  • 初始化:每个测试函数(如:test_fruit1、test_fruit2)执行前,都会调用一次 ret_fruit,生成新字典。
  • 清理:每个测试函数结束后清理资源。
  • 隔离性:每个测试函数操作的字典是完全独立的对象,互不干扰。

字典虽然是可变的,但 ret_fruit 夹具 每次返回一个新字典。所以在 test_fruit1 中修改字典,不会影响 test_fruit2,因为它们操作的是不同的对象。

作用域为 class 的代码理解: 

import pytest


class TestFruit:
    @pytest.fixture(scope="class")
    def ret_fruit(self):
        return {
            "A": "apple",
            "P": "pear",
            "W": "watermelon"
        }

    def test_fruit1(self, ret_fruit):
        ret_fruit["A"] = "avocado"
        print(ret_fruit)

    def test_fruit2(self, ret_fruit):
        print(ret_fruit)

运行结果: 

分析: 

夹具的作用域(scope="class"):

  • 规则:夹具 ret_fruit 在测试类的 第一个测试方法执行前初始化一次,后续所有测试方法共享同一个对象。
  • 初始化:在 TestFruit 类的第一个测试方法(如 test_fruit1)执行前生成字典。
  • 清理:在 TestFruit 类的最后一个测试方法执行后清理。
  • 共享性:类内的所有测试方法(如 test_fruit1 和 test_fruit2)共享同一个字典对象。 

字典是可变对象,在 test_fruit1 中修改 ret_fruit["A"] = "avocado" 会直接影响 test_fruit2 中接收的 ret_fruit,因为 ret_fruit 是同一个字典的引用。 

2.5 pytest的参数化 

2.5.1 什么是参数化测试? 

参数化测试:就是用不同测试数据,去反复运行同一个测试函数,避免重复写类似的测试代码。

举例说明:学过测试的小伙伴应该知道,当我们去测一个登录功能的时候,是会有很多条测试用例去测这个登录功能的。那我们进行登录自动化接口测试的时候,那么登录功能就会被抽象成一个函数,测这个功能的测试数据又有很多。如果每个情况都写一个测试函数,那么代码就会很冗余。参数化就可以让你用一个函数跑遍所有情况。

2.5.2 参数化的使用 

参数化的使用:@pytest.mark.parametrize("参数名", 参数值列表) 

import pytest


def add(a, b):
    return a + b


# 装饰器写法:@pytest.mark.parametrize("参数名", 参数值列表)
@pytest.mark.parametrize("a, b, expected", [(1, 2, 3), (2, 3, 5)])
def test_add(a, b, expected):
    assert add(a, b) == expected

 运行结果:

@pytest.mark.parametrize:这是 pytest 提供的参数化装饰器。 

第一个参数:“参数名” 是字符串,多个参数用逗号隔开(如 "a, b, expected")。

第二个参数:是一个列表,列表中的每个元素是一组参数值(如 (1, 2, 3)对应一次测试)。

测试函数参数:参数名必须和装饰器中的参数名一一对应(如 a, b, expected)。

上述代码执行测试时,pytest会自动生成 2 个测试用例:

  • 用 a = 1, b = 2, expected = 3 运行一次 test_add。
  • 用 a = 2, b = 3, expected = 5 运行一次 test_add。

注意:实际中参数值列表部分,通常会采用调用其他函数(获取文件数据函数)获取对应的返回值,来获取参数值列表部分。这样就能够实现代码与数据的分离。

3. pytest的高级功能 

3.1 标记(Mark) 

3.1.1 跳过测试 

跳过测试:@pytest.mark.skip 和 @pytest.mark.skipif 

作用:在某些条件下跳过测试,避免执行不必要或暂时无法运行的测试。 

直接跳过: 

import pytest


@pytest.mark.skip(reason="该功能尚未实现")
def test_feature_not_implemented():
    assert False  # 不会执行

运行结果: 

动态条件跳过: 

import pytest


@pytest.mark.skipif(1 == 1, reason="条件成立跳过")
def test_condition_skipping():
    pass

运行结果: 

这个只有条件成立才会跳过,不成立则不会跳过。

3.1.2 预期失败 

预期失败:@pytest.mark.xfail 

作用:标记已知会失败的测试,测试失败时不计入错误统计(显示为 xfailed) 

import pytest


@pytest.mark.xfail
def test_beta_feature():
    assert False

运行结果: 

3.2 异常测试 

作用:验证代码是否抛出预期的异常类型和错误信息 

基础异常断言:pytest.raises  

import pytest


def test_divide_by_zero():
    with pytest.raises(ZeroDivisionError):
        10 / 0

 结果抛出 ZeroDivisionError,才能测试通过。

运行结果: 

装饰器方式:@pytest.mark.xfail(raises=...) 

适用于整个测试函数都预期抛出异常的场景: 

import pytest


@pytest.mark.xfail(raises=IndexError)
def test_out_of_bounds():
    my_list = [1, 2, 3]
    return my_list[100]  # 预期会抛出IndexError

运行结果: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2398635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设备驱动与文件系统:02 键盘

操作系统中键盘驱动的讲解 在这一讲中,我将为大家讲解键盘相关内容。从上一讲开始,我们进入了操作系统第四个部分的学习,也就是操作系统对设备的驱动与管理。 上一讲我们探讨的是显示器,并且提到,一个终端设备是由显示…

交通违法拍照数据集,可识别接打电话,不系安全带的行为,支持YOLO,COCO JSON,VOC XML格式的标注数据集 最高正确识别率可达88.6%

交通违法拍照数据集 数据集概述 数据来源:交通监控摄像头、执法记录仪、公开数据集数据类型:图像、视频、元数据(时间、地点、车辆信息)违法类型标注:接打电话、未系安全带 数据采集与标注方法 采集设备&#xff1…

Qt OpenGL 3D 编程入门

Qt 提供了强大的 OpenGL 集成功能,使得在 Qt 应用中实现 3D 图形变得更加简单。以下是使用 Qt 进行 OpenGL 3D 编程的基础知识。 1. 环境配置 创建 Qt 项目 新建 Qt Widgets Application 项目 在 .pro 文件中添加 OpenGL 模块: qmake QT co…

性能优化 - 工具篇:基准测试 JMH

文章目录 Pre引言1. JMH 简介2. JMH 执行流程详解3. 关键注解详解3.1 Warmup3.2 Measurement3.3 BenchmarkMode3.4 OutputTimeUnit3.5 Fork3.6 Threads3.7 Group 与 GroupThreads3.8 State3.9 Setup 与 TearDown3.10 Param3.11 CompilerControl 4. 示例代码与分析4.1 关键点解读…

Nginx网站服务:从入门到LNMP架构实战

🏡作者主页:点击! Nginx-从零开始的服务器之旅专栏:点击! 🐧Linux高级管理防护和群集专栏:点击! ⏰️创作时间:2025年5月30日14点22分 前言 说起Web服务器&#xff0c…

Java面试八股--08-数据结构和算法篇

1、怎么理解时间复杂度和空间复杂度 时间复杂度和空间复杂度一般是针对算法而言,是衡量一个算法是否高效的重要标准。先纠正一个误区,时间复杂度并不是算法执行的时间,在纠正一个误区,算法不单单指冒泡排序之类的,一个…

Java面试八股--06-Linux篇

目录 一、Git 1、工作中git开发使用流程(命令版本描述) 2.Reset与Rebase,Pull与Fetch的区别 3、git merge和git rebase的区别 4、git如何解决代码冲突 5、项目开发时git分支情况 二、Linux 1、Linux常用的命令 2、如何查看测试项目的…

dvwa7——SQL Injection

LOW: f12打开hackbar 一:判断注入类型 输入id1报错 闭合单引号 ,页面恢复正常 所以为单引号字符型 二:开始攻击 1.判断列数 ?id1 order by 2-- 到3的时候开始报错,所以一共两列 2.爆回显位置 ?id-1 union s…

sqlite3 命令行工具详细介绍

一、启动与退出 启动数据库连接 sqlite3 [database_file] # 打开/创建数据库文件(如 test.db) sqlite3 # 启动临时内存数据库 (:memory:) sqlite3 :memory: # 显式启动内存数据库文件不存在时自动创建不指定文件名则使用临时内…

ubuntu 22.04 编译安装nignx 报错 openssl 问题

前言 Ubuntu 20.04 中安装 Nginx (通过传包编译的方式)、开启关闭防火墙、开放端口号 在ubuntu 22.04.3 服务器上照着上面的文章 通过传包编译的方式安装nginx-1.18.0 的时候报错,报错内容如下: src/event/ngx_event_openssl.c: In function ‘ngx_ssl…

线程相关面试题

提示:线程相关面试题,持续更新中 文章目录 一、Java线程池1、Java线程池有哪些核心参数,分别有什么的作用?2、线程池有哪些拒绝策略?3、说一说线程池的执行流程?4、线程池核心线程数怎么设置呢?4、Java线程…

pikachu通关教程-目录遍历漏洞(../../)

目录遍历漏洞也可以叫做信息泄露漏洞、非授权文件包含漏洞等. 原理:目录遍历漏洞的原理比较简单,就是程序在实现上没有充分过滤用户输入的../之类的目录跳转符,导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件。 这里的目录跳转符可以是../…

Maven-生命周期

目录 1.项目对象模型 2.依赖管理模型 3.仓库:用于存储资源,管理各种jar包 4.本地仓库路径 1.项目对象模型 2.依赖管理模型 3.仓库:用于存储资源,管理各种jar包 4.本地仓库路径

Matlab实现LSTM-SVM回归预测,作者:机器学习之心

Matlab实现LSTM-SVM回归预测,作者:机器学习之心 目录 Matlab实现LSTM-SVM回归预测,作者:机器学习之心效果一览基本介绍程序设计参考资料 效果一览 基本介绍 代码主要功能 该代码实现了一个LSTM-SVM回归预测模型,核心流…

Spring Boot 自动配置原理:从入门到精通

Spring Boot 的自动配置是其核心特性之一,它极大地简化了 Spring 应用的开发,让开发者可以专注于业务逻辑,而无需编写大量的配置代码。 本文将深入探讨 Spring Boot 自动配置的原理,帮助你理解其工作机制,并能灵活运用…

腾讯 ovCompose 开源,Kuikly 鸿蒙和 Compose DSL 开源,腾讯的“双”鸿蒙方案发布

近日,腾讯的 ovCompose 和 Kuikly 都发布了全新开源更新,其中 Kuikly 在之前我们聊过,本次 Kuikly 主要是正式开源鸿蒙支持部分和 Compose DSL 的相关支持,而 ovCompose 是腾讯视频团队基于 Compose Multiplatform 生态推出的跨平…

PYTHON调用讯飞C/C++动态库实现离线语音合成并且实时播放

语音合成(Text-to-Speech, TTS)技术在现代应用中扮演着越来越重要的角色,从智能客服到有声读物,从导航系统到辅助工具,TTS技术无处不在。本文将详细介绍如何使用Python结合科大讯飞的离线SDK实现一个本地化的语音合成系统。 技术背景 离线语…

黑马Java面试笔记之 消息中间件篇(RabbitMQ)

一. 消息丢失问题 RabbitMQ如何保证消息不丢失? 使用场景有: 异步发送(验证码、短信、邮件... )MYSQL和Redis,ES之间的数据同步分布式事务削峰填谷...... 消息丢失原因会有三种情况,分别分析一下 1.1 生…

Redisson学习专栏(五):源码阅读及Redisson的Netty通信层设计

文章目录 前言一、分布式锁核心实现:RedissonLock源码深度解析1.1 加锁机制:原子性与重入性实现1.2 看门狗机制:锁自动续期设计1.3 解锁机制:安全释放与通知1.4 锁竞争处理:等待队列与公平性1.5 容错机制:异…

结合 AI 生成 mermaid、plantuml 等图表

AI 画图 AI 画图并不是真的让 AI 画一个图片,而是让 AI 根据你的需求,生成对应的需求文本,再根据 “文本画图” 来生成图片。 Mermaid mermaid 支持流程图、时序图、架构图等等多种图片绘制。当然最终生成的效果和样式会根据不同的“文本代…