pytest 通过实例讲清单元测试、集成测试、测试覆盖率

1. 单元测试

概念

  • 定义: 单元测试是对代码中最小功能单元的测试,通常是函数或类的方法。
  • 目标: 验证单个功能是否按照预期工作,而不依赖其他模块或外部资源。
  • 特点: 快速、独立,通常是开发者最先编写的测试。

示例:pytest 实现单元测试

# 功能模块:一个简单的数学函数
def add(x, y):"""加法函数"""return x + ydef divide(x, y):"""除法函数,包含除零检查"""if y == 0:raise ValueError("Cannot divide by zero")return x / y# 测试模块:单元测试
def test_add():"""测试 add 函数"""assert add(2, 3) == 5  # 正常情况assert add(-1, 1) == 0  # 边界值assert add(0, 0) == 0  # 特殊情况def test_divide():"""测试 divide 函数"""assert divide(10, 2) == 5  # 正常情况with pytest.raises(ValueError, match="Cannot divide by zero"):divide(1, 0)  # 测试除零异常

执行命令

运行单元测试:

pytest test_example.py

优点

  • 快速反馈代码问题。
  • 单一功能模块的高覆盖率。

2. 集成测试

概念

  • 定义: 集成测试是验证多个模块的交互行为是否正常,确保它们组合在一起能够按预期工作。
  • 目标: 检查模块之间的接口和协作行为,可能涉及数据库、API 或文件系统等外部依赖。
  • 特点: 比单元测试慢,但更贴近实际场景。

示例:pytest 实现集成测试

使用数据库模拟的场景

假设我们有一个用户管理模块,需要测试用户的创建、查询和删除功能:

# 功能模块:用户管理
class UserDatabase:"""模拟用户数据库"""def __init__(self):self.users = {}def add_user(self, username, email):"""添加用户"""if username in self.users:raise ValueError("User already exists")self.users[username] = emaildef get_user(self, username):"""获取用户"""return self.users.get(username)def delete_user(self, username):"""删除用户"""if username in self.users:del self.users[username]else:raise ValueError("User does not exist")# 测试模块:集成测试
def test_user_database():"""测试用户数据库模块的集成功能"""db = UserDatabase()# 添加用户db.add_user("alice", "alice@example.com")assert db.get_user("alice") == "alice@example.com"# 删除用户db.delete_user("alice")assert db.get_user("alice") is None# 测试异常情况with pytest.raises(ValueError, match="User does not exist"):db.delete_user("alice")

执行命令

运行集成测试:

pytest test_example.py

单元测试与集成测试的区别

特性单元测试集成测试
测试范围单一模块或函数多个模块之间的交互
目标验证单独功能是否正确验证整体功能是否按预期工作
速度快速较慢
复杂度较低较高,可能涉及外部依赖
测试工具模拟对象 (Mock)实际环境或部分模拟环境

3. pytest 中的 Mock 模拟(用于集成测试中的外部依赖)

在集成测试中,我们可能需要模拟外部依赖(如数据库、API)。pytest 支持使用 unittest.mock 来实现 Mock。

示例:模拟外部 API

假设我们有一个函数需要从外部 API 获取数据:

# 功能模块:从外部 API 获取数据
def fetch_data(api_client):"""从外部 API 客户端获取数据"""response = api_client.get("/data")if response.status_code == 200:return response.json()else:raise ValueError("Failed to fetch data")
测试:使用 Mock 模拟 API
from unittest.mock import MagicMockdef test_fetch_data():"""测试 fetch_data 函数,使用 Mock 模拟 API 行为"""# 创建 Mock API 客户端mock_client = MagicMock()# 模拟成功响应mock_client.get.return_value.status_code = 200mock_client.get.return_value.json.return_value = {"key": "value"}# 调用函数并验证返回值result = fetch_data(mock_client)assert result == {"key": "value"}# 验证 API 是否被正确调用mock_client.get.assert_called_once_with("/data")

运行测试

使用以下命令运行测试:

pytest test_example.py

4. 测试组合:单元测试 + 集成测试

实际开发中,建议结合单元测试和集成测试:

  1. 单元测试:覆盖每个功能单元,确保模块内部逻辑正确。
  2. 集成测试:验证模块之间的交互和整体功能。

最佳实践

  • 单元测试优先: 先确保每个功能单元稳定。
  • 集成测试补充: 验证整体流程时,再引入集成测试。
  • Mock 外部依赖: 在集成测试中尽量减少对真实资源(数据库、网络)的依赖。

什么是项目的测试覆盖率?

测试覆盖率(Test Coverage)是衡量一个项目中有多少代码被测试用例覆盖的指标。它表示项目代码的质量保证程度。测试覆盖率通常以百分比的形式表示,如 80% 表示代码中 80% 的部分已经被测试用例运行过。

覆盖率分类
  1. 行覆盖率(Line Coverage)
    检测每一行代码是否被执行。

  2. 分支覆盖率(Branch Coverage)
    检测代码中的条件语句(如 if-else)的所有分支是否都被测试。

  3. 函数覆盖率(Function Coverage)
    检测所有函数是否被调用。

  4. 路径覆盖率(Path Coverage)
    检测所有可能的执行路径是否都被测试。

为什么测试覆盖率重要?
  1. 质量保证:确保关键代码路径经过充分测试。
  2. 维护性:发现未被测试的代码,优化测试用例。
  3. 团队规范:强制要求开发者在提交代码前编写测试。

如何计算测试覆盖率?

工具

在 Python 项目中,通常使用以下工具计算测试覆盖率:

  1. pytest-cov:配合 pytest 使用,易于集成。
  2. Coverage.py:独立的覆盖率工具,可生成详细的覆盖率报告。
  3. CodecovCoveralls:托管服务,用于在 GitHub 等平台展示测试覆盖率。

在 GitHub 上展示测试覆盖率

许多开源项目在 GitHub 上会显示覆盖率指标,通过徽章(Badge)的形式展示,通常借助 CodecovCoveralls 服务实现。

如何在 GitHub 项目中添加测试覆盖率?
1. 安装依赖

确保已安装以下工具:

pip install pytest pytest-cov
pip install codecov
2. 配置 pytest-cov

在项目中运行测试并生成覆盖率报告:

pytest --cov=my_project --cov-report=xml

这将生成一个 coverage.xml 文件,供上传到 Codecov 或其他服务。

3. 集成 Codecov

(1)登录 Codecov 并连接你的 GitHub 项目。
(2)在项目根目录添加一个 .github/workflows/codecov.yml 文件:

name: CIon:push:branches:- mainjobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Set up Pythonuses: actions/setup-python@v4with:python-version: '3.9'- name: Install dependenciesrun: |python -m pip install --upgrade pippip install pytest pytest-cov codecov- name: Run tests with coveragerun: |pytest --cov=my_project- name: Upload coverage to Codecovuses: codecov/codecov-action@v3with:file: ./coverage.xml

(3)提交后,GitHub Actions 会自动运行测试并上传覆盖率到 Codecov。

4. 添加徽章

在 Codecov 项目的设置中获取徽章链接,将其添加到你的 README.md 文件中,例如:

[![codecov](https://codecov.io/gh/<username>/<repo>/branch/main/graph/badge.svg)](https://codecov.io/gh/<username>/<repo>)

覆盖率目标

  1. 行业标准

    • 一般项目:60%-80% 及格。
    • 关键项目:95%+(例如金融系统、医疗系统)。
  2. 不能盲目追求100%:覆盖率高不一定代表没有 bug,关注测试的质量比单纯提高覆盖率更重要。

通过这些步骤,你的项目可以在 GitHub 上显示测试覆盖率,并增强项目的专业性和可信度!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨标签通信的几种方式

以前面试被问到过&#xff0c;就了解了一下。还有其他方式&#xff0c;但是实际开发中&#xff0c;使用第一个就可以了 目录 1. 使用BroadcastChannel 2. 使用SharedWorker 3. 使用webSocket 1. 使用BroadcastChannel 它允许同源&#xff08;协议、域名、端口都相同&#x…

深度神经网络模型压缩学习笔记二:离线量化算法和工具、实现原理和细节

文章目录 一、离线量化基础概念1&#xff09;离线量化定义2&#xff09;离线量化优缺点3&#xff09;如何生产一个硬件能跑的量化模型&#xff1f;4&#xff09;离线量化的类型5&#xff09;如何计算scale&#xff0c;zero_point?6&#xff09;离线量化概念7&#xff09;PTQ与…

HTML详解(1)

1.HTML定义 HTML&#xff1a;超文本标记语言。超文本&#xff1a;通过链接可以把多个网页链接到一起标记&#xff1a;标签&#xff0c;带括号的文本后缀&#xff1a;.html 标签语法&#xff1a;<strong>需加粗文字</strong> 成对出现&#xff0c;中间包裹内容&l…

【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 文章题目&#xff1a;Java技术深度剖析&#xff1a;从分库分表到微服务的核心问题解析 摘要&#xff1a; 本…

Jmeter中的配置原件

2&#xff09;配置原件 1--CSV Data Set Config 用途 参数化测试&#xff1a;从CSV文件中读取数据&#xff0c;为每个请求提供不同的参数值。数据驱动测试&#xff1a;使用外部数据文件来驱动测试&#xff0c;使测试更加灵活和可扩展。 配置步骤 准备CSV文件 创建一个CSV文…

Redis持久化、主从及哨兵架构详解

Redis持久化 RDB快照&#xff08;snapshot&#xff09; 在默认情况下&#xff0c;Redis将内存数据库快照保存在名字为dump.rdb的二进制文件中。 你可以对Redis进行设置&#xff0c;让它在“N秒内数据集至少有M个改动”这一条件被满足时&#xff0c;自动保存一次数据集。 比…

双向链表、循环链表、栈

双向循环链表 class Node:#显性定义出构造函数def __init__(self,data):self.data data #普通节点的数据域self.next None #保存下一个节点的链接域self.prior None #保存前一个节点饿链接域 class DoubleLinkLoop:def __init__(self, node Node):self.head nodeself.siz…

【青牛科技】D1671 75Ω 带4级低通滤波的单通道视频放大电 路芯片介绍

概 述 &#xff1a; D1671是 一 块 带 4级 低 通 滤 波 的 单 通 道 视 频 放 大 电 路 &#xff0c; 可 在3V或5V的 低 电 压 下 工 作 。 该 电 路 用 在 有 TV影 象 输 出 功 能 的 产 品 上 面&#xff0c;比如 机 顶 盒 &#xff0c;监 控 摄 象 头 &#xff0c;DVD&#…

Linux服务器生成SSH 密钥对与 GitLab 仓库进行交互

目录 生成 SSH 密钥对 将公钥添加到 GitLab 测试 SSH 连接 生成 SSH 密钥对 在执行脚本的机器上打开终端&#xff0c;执行以下命令&#xff08;假设使用默认的 RSA 算法&#xff0c;一路回车使用默认设置即可&#xff0c;也可以根据需要指定其他算法和参数&#xff09;&…

关于SpringBoot集成Kafka

关于Kafka Apache Kafka 是一个分布式流处理平台&#xff0c;广泛用于构建实时数据管道和流应用。它能够处理大量的数据流&#xff0c;具有高吞吐量、可持久化存储、容错性和扩展性等特性。 Kafka一般用作实时数据流处理、消息队列、事件架构驱动等 Kafka的整体架构 ZooKeeper:…

在Unity中实现物体动画的完整流程

在Unity中&#xff0c;动画是游戏开发中不可或缺的一部分。无论是2D还是3D游戏&#xff0c;动画都能为游戏增添生动的视觉效果。本文将详细介绍如何在Unity中为物体添加动画&#xff0c;包括资源的准备、播放组件的添加、动画控制器的创建以及动画片段的制作与调度。 1. 准备动…

自定义协议

1. 问题引入 问题&#xff1a;TCP是面向字节流的&#xff08;TCP不关心发送的数据是消息、文件还是其他任何类型的数据。它简单地将所有数据视为一个字节序列&#xff0c;即字节流。这意味着TCP不会对发送的数据进行任何特定的边界划分&#xff0c;它只是确保数据的顺序和完整…

Spring Boot 3.4.0 发行:革新与突破的里程碑

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

android 11添加切换分屏功能

引言 自Android 7开始官方就支持分屏显示,但没有切换分屏的功能,即交换上下屏幕。直到Android 13开始才支持切换分屏,操作方式是:分屏模式下双击中间分割线就会交换上下屏位置。本文的目的就是在Android 11上实现切换分屏的功能。 下图是Android13切换分屏演示 切换分屏…

PyTorch基础05_模型的保存和加载

目录 一、模型定义组件——重构线性回归 二、模型的加载和保存 2、序列化保存对象和加载 3、保存模型参数 一、模型定义组件——重构线性回归 回顾之前的手动构建线性回归案例&#xff1a; 1.构建数据集&#xff1b;2.加载数据集(数据集转换为迭代器)&#xff1b;3.参数初…

JavaScript核心语法(3)

前两篇文章大概把JavaScript的基础语法讲了一下&#xff0c;这篇文章主要讲讲ES6的核心语法。ES6的核心语法说实话其实有点多&#xff0c;我重点挑一些经常在项目中用到的来讲&#xff0c;其他一些我没怎么见过的就不讲了。 目录 1.变量和常量 变量&#xff08;let 和 var&a…

爬虫开发(5)如何写一个CSDN热门榜爬虫小程序

笔者 綦枫Maple 的其他作品&#xff0c;欢迎点击查阅哦~&#xff1a; &#x1f4da;Jmeter性能测试大全&#xff1a;Jmeter性能测试大全系列教程&#xff01;持续更新中&#xff01; &#x1f4da;UI自动化测试系列&#xff1a; SeleniumJava自动化测试系列教程❤ &#x1f4da…

NIO三大组件

现在互联网环境下&#xff0c;分布式系统大相径庭&#xff0c;而分布式系统的根基在于网络编程&#xff0c;而netty恰恰是java领域的网络编程的王者&#xff0c;如果要致力于并发高性能的服务器程序、高性能的客户端程序&#xff0c;必须掌握netty网络编程。 NIO基础 NIO是从ja…

34 基于单片机的指纹打卡系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52RC&#xff0c;采用两个按键替代指纹&#xff0c;一个按键按下&#xff0c;LCD12864显示比对成功&#xff0c;则 采用ULN2003驱动步进电机转动&#xff0c;表示开门&#xff0c;另一个…

李宏毅机器学习课程知识点摘要(14-18集)

线性回归&#xff0c;逻辑回归&#xff08;线性回归sigmoid&#xff09;&#xff0c;神经网络 linear regression &#xff0c; logistic regression &#xff0c; neutral network 里面的偏导的相量有几百万维&#xff0c;这就是neutral network的不同&#xff0c;他是…