Unitest和pytest使用方法

news2025/4/23 7:09:56

unittest 是 Python 自带的单元测试框架,用于编写和运行可重复的测试用例。它的核心思想是通过断言(assertions)验证代码的行为是否符合预期。以下是 unittest 的基本使用方法:


1. 基本结构

1.1 创建测试类
  • 继承 unittest.TestCase,每个测试用例对应一个方法。
  • 测试方法必须 test_ 开头,否则不会被自动识别为测试用例。
import unittest

class TestMathOperations(unittest.TestCase):
    def test_addition(self):
        self.assertEqual(1 + 1, 2)  # 断言 1+1=2
1.2 前置与后置方法
  • setUp(): 在每个测试方法执行前运行(如初始化资源)。
  • tearDown(): 在每个测试方法执行后运行(如清理资源)。
  • setUpClass() / tearDownClass(): 在整个测试类的开始/结束时运行(需用 @classmethod 修饰)。
class TestExample(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("整个测试类开始前执行")

    def setUp(self):
        print("每个测试方法开始前执行")

    def test_example(self):
        self.assertTrue(True)

    def tearDown(self):
        print("每个测试方法结束后执行")

    @classmethod
    def tearDownClass(cls):
        print("整个测试类结束后执行")

2. 断言方法

unittest 提供了丰富的断言方法,常用如下:

方法说明
assertEqual(a, b)检查 a == b
assertTrue(x)检查 x 为 True
assertFalse(x)检查 x 为 False
assertRaises(Error, func, *args)检查函数 func 是否抛出 Error 异常
assertIn(a, b)检查 ab
assertIsNone(x)检查 x 是 None
def test_assertions(self):
    self.assertEqual(3 * 3, 9)
    self.assertIn(2, [1, 2, 3])
    with self.assertRaises(ZeroDivisionError):
        _ = 1 / 0

3. 运行测试

3.1 通过代码运行

在脚本末尾添加:

if __name__ == "__main__":
    unittest.main()
3.2 通过命令行运行
# 运行单个测试模块
python -m unittest test_module.py

# 自动发现并运行所有测试(推荐)
python -m unittest discover
3.3 指定运行特定测试
# 运行单个测试类
python -m unittest test_module.TestClass

# 运行单个测试方法
python -m unittest test_module.TestClass.test_method

4. 测试套件(Test Suite)

手动组织多个测试用例:

suite = unittest.TestSuite()
suite.addTest(TestMathOperations("test_addition"))
suite.addTest(TestExample("test_example"))

runner = unittest.TextTestRunner()
runner.run(suite)

5. 高级用法

5.1 跳过测试

使用装饰器跳过某些测试:

@unittest.skip("跳过原因")
def test_skipped(self):
    self.fail("不会执行")

@unittest.skipIf(condition, "条件满足时跳过")
def test_conditional_skip(self):
    pass
5.2 参数化测试

unittest 本身不支持参数化,但可通过第三方库(如 parameterized)实现:

from parameterized import parameterized

class TestParameterized(unittest.TestCase):
    @parameterized.expand([
        (2, 3, 5),
        (0, 0, 0),
    ])
    def test_add(self, a, b, expected):
        self.assertEqual(a + b, expected)
5.3 Mock 对象

使用 unittest.mock 模拟外部依赖:

from unittest.mock import Mock

def test_mock(self):
    mock_obj = Mock(return_value=42)
    self.assertEqual(mock_obj(), 42)

6. 示例项目结构

project/
├── my_code.py       # 被测试的代码
└── tests/
    ├── __init__.py
    └── test_code.py # 测试代码

总结

unittest 是 Python 测试的基石,适合中小型项目。对于复杂场景,可以结合第三方库(如 pytest)增强功能。核心步骤:

  1. 继承 TestCase 编写测试类。
  2. 使用 test_ 前缀定义测试方法。
  3. 通过断言验证逻辑。
  4. 利用 setUp()/tearDown() 管理资源。
  5. 运行测试并分析结果。

pytest 是 Python 中最流行的第三方测试框架,以其简洁的语法、强大的功能和灵活的扩展性著称。相比 unittestpytest 更注重代码的可读性和可维护性,同时支持丰富的插件生态系统。以下是 pytest 的核心使用方法:


1. 安装 pytest

pip install pytest

2. 基本用法

2.1 编写测试函数
  • 测试函数名需以 test_ 开头(或 _test 结尾)。
  • 断言直接使用 Python 原生 assert 语句,无需记忆特定断言方法。
# test_sample.py
def test_addition():
    assert 1 + 1 == 2

def test_list_contains():
    numbers = [1, 2, 3]
    assert 2 in numbers
2.2 运行测试
# 运行当前目录所有测试
pytest

# 运行指定文件
pytest test_sample.py

# 运行指定函数
pytest test_sample.py::test_addition

# 显示详细输出(-v 显示用例名称,-s 打印输出)
pytest -v -s

3. 断言增强

pytest 的断言失败信息更直观,能自动展示上下文差异(如列表、字典比较):

def test_failure_example():
    expected = {"a": 1, "b": 2}
    actual = {"a": 1, "b": 3}
    assert expected == actual

运行后输出:

AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3}
  Differing items:
  {'b': 2} != {'b': 3}

4. Fixture(依赖注入)

pytestfixture 机制用于管理测试的依赖资源(如数据库连接、临时文件),支持复用和共享。

4.1 定义 Fixture
import pytest

@pytest.fixture
def database_connection():
    conn = create_db_connection()  # 初始化资源
    yield conn                     # 返回资源
    conn.close()                   # 清理资源
4.2 使用 Fixture

在测试函数中通过参数名直接调用:

def test_query(database_connection):
    result = database_connection.query("SELECT * FROM users")
    assert len(result) > 0
4.3 Fixture 作用域

通过 scope 参数控制生命周期:

@pytest.fixture(scope="module")  # 作用域:模块级(每个模块执行一次)
def shared_resource():
    return initialize_resource()

5. 参数化测试

使用 @pytest.mark.parametrize 对单条测试用例注入多组参数,避免重复代码。

import pytest

@pytest.mark.parametrize("a, b, expected", [
    (2, 3, 5),
    (0, 0, 0),
    (-1, 5, 4),
])
def test_add(a, b, expected):
    assert a + b == expected

6. 测试异常

使用 pytest.raises 捕获并验证异常:

def test_division_by_zero():
    with pytest.raises(ZeroDivisionError):
        _ = 1 / 0

7. Mock 对象(依赖隔离)

使用 pytest-mock 插件(基于 unittest.mock)模拟外部依赖:

pip install pytest-mock

示例:

def test_mocking(mocker):
    mock_requests = mocker.patch("requests.get")  # 模拟 requests.get
    mock_requests.return_value.status_code = 200
    
    response = requests.get("https://api.example.com")
    assert response.status_code == 200

8. 插件扩展

pytest 支持丰富的插件,例如:

  • pytest-cov: 测试覆盖率统计
  • pytest-xdist: 并行运行测试
  • pytest-django: Django 项目集成
  • pytest-asyncio: 异步测试支持

安装插件:

pip install pytest-cov pytest-xdist

9. 项目结构

project/
├── src/                  # 源代码
│   └── my_module.py
└── tests/               # 测试代码
    ├── __init__.py
    ├── conftest.py      # 全局 Fixture 定义
    ├── test_core.py
    └── test_api.py

10. 与 unittest 兼容

pytest 可以直接运行 unittest 风格的测试用例:

# test_unittest_style.py
import unittest

class TestOldCode(unittest.TestCase):
    def test_legacy(self):
        self.assertEqual(1 + 1, 2)

运行:

pytest test_unittest_style.py

11. 高级功能

  • 标记(Markers)
    @pytest.mark 对测试分类(如跳过、标记为慢测试):

    @pytest.mark.skip(reason="尚未实现")
    def test_unimplemented():
        assert False
    
    @pytest.mark.slow
    def test_long_running():
        # 耗时操作
        pass
    

    运行指定标记的测试:

    pytest -m slow    # 只运行标记为 slow 的测试
    pytest -m "not slow"  # 排除 slow 测试
    
  • Hook 函数
    自定义 pytest 行为(如修改报告输出)。


总结

pytest 的优势:

  1. 简洁性:使用原生 assert,减少样板代码。
  2. 灵活性:Fixture 机制优雅管理测试依赖。
  3. 扩展性:通过插件支持复杂场景(如异步、分布式测试)。
  4. 兼容性:无缝运行 unittestnose 测试。

适合从简单脚本到大型项目的全场景测试需求。

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

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

相关文章

webpack基础使用了解(入口、出口、插件、加载器、优化、别名、打包模式、环境变量、代码分割等)

目录 1、webpack简介2、简单示例3、入口(entry)和输出(output)4、自动生成html文件5、打包css代码6、优化(单独提取css代码)7、优化(压缩过程)8、打包less代码9、打包图片10、搭建开发环境(webpack-dev-server&#xf…

微信小程序 van-dropdown-menu

点击其他按钮,关闭van-dropdown-menu下拉框 DropdownMenu 引入页面使用index.wxmlindex.scssindex.ts(重点)index.ts(全部) DropdownMenu 引入 在app.json或index.json中引入组件 "usingComponents": {"van-dropdown-menu": "vant/weapp…

智驱未来:AI大模型重构数据治理新范式

第一章 数据治理的进化之路 1.1 传统数据治理的困境 在制造业巨头西门子的案例中,其全球200个工厂每天产生1.2PB工业数据,传统人工清洗需要300名工程师耗时72小时完成,错误率高达15%。数据孤岛问题导致供应链决策延迟平均达48小时。 1.2 A…

C++ 蓄水池抽样算法

(1)概念 蓄水池抽样算法(Reservoir Sampling)是一种用于从 大规模数据集(尤其是 流式数据 或 无法预先知晓数据总量 的场景)中 等概率随机抽取固定数量样本 的算法。 (2)实现 我们…

分布式光纤测温技术让森林火灾预警快人一步

2025年春季,多地接连发生森林火灾,累计过火面积超 3万公顷。春季历来是森林草原火灾易发、多发期,加之清明节已到来,生产生活用火活跃,民俗祭祀用火集中,森林火灾风险进一步加大。森林防火,人人…

Vue2 el-checkbox 虚拟滚动解决多选框全选卡顿问题 - 高性能处理大数据量选项列表

一、背景 在我们开发项目中,经常会遇到需要展示大量选项的多选框场景,比如权限配置、数据筛选等。当选项数量达到几百甚至上千条时,传统的渲染方式全选时会非常卡顿,导致性能问题。本篇文章,记录我使用通过虚拟滚动实现…

KUKA机器人KR 3 D1200 HM介绍

KUKA KR 3 D1200 HM是一款小型机器人,型号中HM代表“Hygienic Machine(卫生机械)用于主副食品行业”,也是一款并联机器人。用于执行高速、高精度的抓取任务。这款机器人采用食品级不锈钢设计,额定负载为3公斤&#xff…

【MATLAB第117期】#源码分享 | 基于MATLAB的SSM状态空间模型多元时间序列预测方法(多输入单输出)

【MATLAB第117期】#源码分享 | 基于MATLAB的SSM状态空间模型多元时间序列预测方法(多输入单输出) 引言 本文使用状态空间模型实现失业率递归预测,状态空间模型(State Space Model, SSM)是一种用于描述动态系统行为的…

【Linux】线程ID、线程管理、与线程互斥

📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🌐 C 语言 上篇文章: 【Linux】线程:从原理到实战,全面掌握多线程编程!-CSDN博客 下…

【锂电池SOH估计】RF随机森林锂电池健康状态估计,锂电池SOH估计(Matlab完整源码和数据)

目录 效果一览程序获取程序内容代码分享研究内容基于随机森林(RF)的锂电池健康状态(SOH)估计算法研究摘要1. 引言2. 锂电池SOH评估框架3. 实验与结果分析4. 未来研究方向6. 结论效果一览 程序获取 获取方式一:文章顶部资源处直接下载:【锂电池SOH估计】RF随机森林锂电池…

【Pytorch 中的扩散模型】去噪扩散概率模型(DDPM)的实现

介绍 广义上讲,扩散模型是一种生成式深度学习模型,它通过学习到的去噪过程来创建数据。扩散模型有很多变体,其中最流行的通常是文本条件模型,它可以根据提示生成特定的图像。一些扩散模型(例如 Control-Net&#xff0…

121.在 Vue3 中使用 OpenLayers 实现去掉鼠标右键默认菜单并显示 Feature 信息

🎯 实现效果 👇 本文最终实现的效果如下: ✅ 地图初始化时绘制一个多边形; ✅ 鼠标 右键点击地图任意位置; ✅ 若命中 Feature,则弹出该图形的详细信息; ✅ 移除浏览器默认的右键菜单,保留地图交互的完整控制。 💡 整个功能基于 Vue3 + OpenLayers 完成,采用 Com…

进阶篇 第 6 篇:时间序列遇见机器学习与深度学习

进阶篇 第 6 篇:时间序列遇见机器学习与深度学习 (图片来源: Tara Winstead on Pexels) 在上一篇中,我们探讨了如何通过精心的特征工程,将时间序列预测问题转化为机器学习可以处理的监督学习任务。我们学习了如何创建滞后特征、滚动统计特征…

【音视频】音频解码实战

音频解码过程 ⾳频解码过程如下图所示: FFmpeg流程 关键函数 关键函数说明: avcodec_find_decoder:根据指定的AVCodecID查找注册的解码器。av_parser_init:初始化AVCodecParserContext。avcodec_alloc_context3:为…

DOCA介绍

本文分为两个部分: DOCA及BlueField介绍如何运行DOCA应用,这里以DNS_Filter为例子做大致介绍。 DOCA及BlueField介绍: 现代企业数据中心是软件定义的、完全可编程的基础设施,旨在服务于跨云、核心和边缘环境的高度分布式应用工作…

# 利用迁移学习优化食物分类模型:基于ResNet18的实践

利用迁移学习优化食物分类模型:基于ResNet18的实践 在深度学习的众多应用中,图像分类一直是一个热门且具有挑战性的领域。随着研究的深入,我们发现利用预训练模型进行迁移学习是一种非常有效的策略,可以显著提高模型的性能&#…

洗车小程序系统前端uniapp 后台thinkphp

洗车小程序系统 前端uniapp 后台thinkphp 支持多门店 分销 在线预约 套餐卡等

HCIP(综合实验2)

1.实验拓补图 2.实验要求 1.根据提供材料划分VLAN以及IP地址,PC1/PC2属于生产一部员工划分VLAN10,PC3属于生产二部划分VLAN20 2.HJ-1HJ-2交换机需要配置链路聚合以保证业务数据访问的高带宽需求 3.VLAN的放通遵循最小VLAN透传原则 4.配置MSTP生成树解决二层环路问题…

Linux mmp文件映射补充(自用)

addr一般为NULL由OS指明,length所需长度(4kb对齐),prot(权限,一般O_RDWR以读写), flag(MAP_SHARED(不刷新到磁盘上,此进程独有)和MAP_PRIVATE(刷新…

单元测试学习笔记(一)

自动化测试 通过测试工具/编程模拟手动测试步骤,全自动半自动执行测试用例,对比预期输出和实际输出,记录并统计测试结果,减少重复的工作量。 单元测试 针对最小的单元测试,Java中就是一个一个的方法就是一个一个的单…