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.mzph.cn/web/60928.shtml

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

相关文章

Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64

yum install 报错: Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 CentOS7的SCL源在2024年6月30日停止维护了。 当scl源里面默认使用了centos官方的地址&#xff0c;无法连接&#xff0c;需要替换为阿里云。 cd /etc/yum.repos.d/ 找到 CentOS-SCLo-scl.repo 和…

Vue前端开发-slot传参

slot 又称插槽&#xff0c;它是在子组件中为父组件提供的一个占位符&#xff0c;使用来表示&#xff0c;通过这个占位符&#xff0c;父组件可以向中填充任意的内容代码&#xff0c;这些代码将自动替换占位符的位置&#xff0c;从而轻松实现在父组件中控制子组件内容的需求。 作…

如何在 Ubuntu 22.04 上安装带有 Nginx 的 ELK Stack

今天我们来聊聊如何在 Ubuntu 22.04 服务器上安装 ELK Stack&#xff0c;并集成 Nginx 作为 Web 服务器&#xff0c;同时使用 Let’s Encrypt Certbot 进行 SSL 认证。ELK Stack&#xff0c;包括 Elasticsearch、Logstash 和 Kibana&#xff0c;是一套强大的工具&#xff0c;用…

快速理解微服务中Sentinel怎么实现限流

Sentinel是通过动态管理限流规则&#xff0c;根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源&#xff1a;在Sentinel中&#xff0c;资源可以是URL、方法等&#xff0c;用于标识需要进行限流的请求&#xff1b;(在Sentinel中&#xff0c;需要我们去告诉Sentinel哪些…

基于单片机的智慧小区人脸识别门禁系统

本设计基于单片机的智慧小区人脸识别门禁系统。由STM32F103C8T6单片机核心板、显示模块、摄像头模块、舵机模块、按键模块和电源模块组成。可以通过摄像头模块对进入人员人脸数据进行采集&#xff0c;识别成功后&#xff0c;舵机模块动作&#xff0c;模拟门禁打开&#xff0c;门…

llama-factory 系列教程 (七),Qwen2.5-7B-Instruct 模型微调与vllm部署详细流程实战

文章目录 介绍llama-factory 安装装包下载模型 微调模型数据集训练模型 微调后的模型推理 介绍 时隔已久的 llama-factory 系列教程更新了。本篇文章是第七篇&#xff0c;之前的六篇&#xff0c;大家酌情选看即可。 因为llama-factory进行了更新&#xff0c;我前面几篇文章的实…

利用Docker容器技术部署发布web应用程序

Docker是什么&#xff1f; docker 是一个开源的应用容器引擎&#xff0c;可以帮助开发者打包应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化&#xff0c;容器是完全使用沙箱机制&#xff0c;相互之间不会有任何…

SpringCloud框架学习(第五部分:SpringCloud Alibaba入门和 nacos)

目录 十二、SpringCloud Alibaba入门简介 1. 基本介绍 2.作用 3.版本选型 十三、 SpringCloud Alibaba Nacos服务注册和配置中心 1.简介 2.各种注册中心比较 3.下载安装 4.Nacos Discovery服务注册中心 &#xff08;1&#xff09; 基于 Nacos 的服务提供者 &#xf…

Linux—进程概念学习-03

目录 Linux—进程学习—31.进程优先级1.1Linux中的进程优先级1.2修改进程优先级—top 2.进程的其他概念3.进程切换4.环境变量4.0环境变量的理解4.1环境变量的基本概念4.2添加环境变量—export4.3Linux中环境变量的由来4.4常见环境变量4.5和环境变量相关的命令4.6通过系统调用获…

信创改造 - TongRDS 替换 Redis

记得开放 6379 端口哦 1&#xff09;首先在服务器上安装好 TongRDS 2&#xff09;替换 redis 的 host&#xff0c;post&#xff0c;passwd 3&#xff09;TongRDS 兼容 jedis # 例如&#xff1a;更改原先 redis 中对应的 host&#xff0c;post&#xff0c;passwd 改成 TongRDS…

Python 爬虫入门教程:从零构建你的第一个网络爬虫

网络爬虫是一种自动化程序&#xff0c;用于从网站抓取数据。Python 凭借其丰富的库和简单的语法&#xff0c;是构建网络爬虫的理想语言。本文将带你从零开始学习 Python 爬虫的基本知识&#xff0c;并实现一个简单的爬虫项目。 1. 什么是网络爬虫&#xff1f; 网络爬虫&#x…

从0到1部署Tomcat和添加servlet(IDEA2024最新版详细教程)

本文不仅细化了每一个步骤&#xff0c;实现了从0到1部署Tomcat和添加servlet。还针对IDEA2024版和以前的版本在部署上的区别&#xff0c;做了详细介绍&#xff0c;尤其是add framework support部分。与此同时&#xff0c;针对控制台中文乱码问题&#xff0c;本文也给出了详细解…

书生大模型实战营第四期-入门岛-4. maas课程任务

书生大模型实战营第四期-入门岛-4. maas课程任务 任务一、模型下载 任务内容 使用Hugging Face平台、魔搭社区平台&#xff08;可选&#xff09;和魔乐社区平台&#xff08;可选&#xff09;下载文档中提到的模型&#xff08;至少需要下载config.json文件、model.safetensor…

相亲交友小程序项目介绍

一、项目背景 在当今快节奏的社会生活中&#xff0c;人们忙于工作和事业&#xff0c;社交圈子相对狭窄&#xff0c;寻找合适的恋爱对象变得愈发困难。相亲交友作为一种传统而有效的社交方式&#xff0c;在现代社会依然有着巨大的需求。我们的相亲交友项目旨在为广大单身人士提…

初级数据结构——二叉树题库(c++)

这里写目录标题 前言[1.——965. 单值二叉树](https://leetcode.cn/problems/univalued-binary-tree/)[2.——222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)[3.——144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-…

【前端】ES6基础

1.开发工具 vscode地址 :https://code.visualstudio.com/download, 下载对应系统的版本windows一般都是64位的 安装可以自选目录&#xff0c;也可以使用默认目录 插件&#xff1a; 输入 Chinese&#xff0c;中文插件 安装&#xff1a; open in browser&#xff0c;直接右键文件…

25A物联网微型断路器 智慧空开1P 2P 3P 4P-安科瑞黄安南

微型断路器&#xff0c;作为现代电气系统中不可或缺的重要组件&#xff0c;在保障电路安全与稳定运行方面发挥着关键作用。从其工作原理来看&#xff0c;微型断路器通过感知电流的异常变化来迅速作出响应。当电路中的电流超过预设的安全阈值时&#xff0c;其内部的电磁感应装置…

数据结构--Map和Set

目录 一.二叉搜索树1.1 概念1.2 二叉搜索树的简单实现 二.Map2.1 概念2.2 Map常用方法2.3 Map使用注意点2.4 TreeMap和HashMap的区别2.5 HashMap底层知识点 三.Set3.1 概念3.2 Set常用方法3.3 Set使用注意点3.4 TreeSet与HashSet的区别 四.哈希表4.1 概念4.2 哈希冲突与避免4.3…

计算机操作系统——进程控制(Linux)

进程控制 进程创建fork&#xff08;&#xff09;函数fork() 的基本功能fork() 的基本语法fork() 的工作原理fork() 的典型使用示例fork() 的常见问题fork() 和 exec() 结合使用总结 进程终止与$进程终止的本质进程终止的情况正常退出&#xff08;Exit&#xff09;由于信号终止非…

【ArcGIS Pro实操第10期】统计某个shp文件中不同区域内的站点数

统计某个shp文件中不同区域内的站点数 方法 1&#xff1a;使用“空间连接 (Spatial Join)”工具方法 2&#xff1a;使用“点计数 (Point Count)”工具方法 3&#xff1a;通过“选择 (Select by Location)”统计方法 4&#xff1a;通过“Python 脚本 (ArcPy)”实现参考 在 ArcGI…