python单元测试
文章目录
- 单元测试
- 定义
- 断言函数
- Test Fixtures
- Mock
- patch
- 装饰器模拟(首选)
- 上下文管理器模拟
- 手动模拟
- 测试实例
- 测试覆盖率
- pytest框架
- 起步
- 安装使用
- 常用参数
- 跳过测试
- @pytest.fixture
- conftest.py
- 参数化测试
- 数据库查询的mock
- 覆盖率
单元测试
定义
单元测试是指一个自动化的测试:
- 用来验证一小段代码的正确性
- 可以快速执行
- 在独立的环境中执行
断言函数
assertEqual
assertNotEqual
assertTrue
assertFalse
assertIs
assertIsNot
assertIsNone
assertIsNotNone
assertIn
assertNotIn
assertIsInstance
assertNotIsInstance
assertRaises
示例一:assertEqual
class Calculator:def add(self, *args):ret = 0for item in args:ret += itemreturn ret
from unittest import TestCasefrom server.app import Calculatorclass TestCalculator(TestCase):def test_add(self):calculator = Calculator()expect_result = 10actual_result = calculator.add(1, 2, 3, 4)self.assertEqual(expect_result, actual_result)
示例二:assertRaises
class Service:def download_img(self, url: str):if url:return Trueraise ValueError("url error")
from unittest import TestCase
from server.app import Serviceclass TestService(TestCase):def test_download_img_success(self):service = Service()ret = service.download_img("http://www.baidu.com/1.png")self.assertTrue(ret)def test_download_img_with_exception(self):service = Service()with self.assertRaises(ValueError):service.download_img("")
Test Fixtures
在测试方法执行之前或者之后执行的函数或者方法被称为Test Fixtures
- module级别的Fixtures:
setUpModule,tearDownModule - class级别的Fixtures:
setUpClass,tearDownClass - method级别的Fixtures:
setUp,tearDown
class Service:def download_img(self, url: str):if url:return Trueraise ValueError("url error")
from unittest import TestCase
from server.app import Servicedef setUpModule():print("执行module前...")def tearDownModule():print("执行module后...")class TestService(TestCase):@classmethoddef setUpClass(cls):print("执行class前...")@classmethoddef tearDownClass(cls):print("执行class后...")def setUp(self):self.service = Service()print("执行任意测试方法前...")def tearDown(self):print("执行任意测试方法后...")def test_download_img_success(self):ret = self.service.download_img("http://www.baidu.com/1.png")self.assertTrue(ret)def test_download_img_with_exception(self):with self.assertRaises(ValueError):self.service.download_img("")
执行module前...
执行class前...
执行任意测试方法前...
执行任意测试方法后...
执行任意测试方法前...
执行任意测试方法后...
执行class后...
执行module后...
Mock
模拟函数,方法,类的行为。
-
Mock:主要模拟指定的方法和属性
-
MagicMock:Mock的子类,同时模拟了很多Magic方法(
__len__,__str__方法等)
示例一:
from unittest.mock import Mockdef test_hello():hello = Mock()hello.find_user.return_value = {'name': '旺财','age': 1}print(hello.find_user())if __name__ == '__main__':test_hello()
{'name': '旺财', 'age': 1}
示例二:
class Student:def __init__(self, id: int, name: str):self.id = idself.name = namedef find_name_by_id(id):passdef save_student(student):passdef chang_name(id: int, new_name: str):student = find_name_by_id(id)if student:student.name = new_namesave_student(student)
from unittest.mock import Mock
from unittest import TestCase
from server.app import chang_name
from server import appclass TestService(TestCase):def test_change_name_with_record(self):service.find_name_by_id = Mock()student = Mock(id=1, name='旧名字')service.find_name_by_id.return_value = studentservice.save_student = Mock()chang_name(1, '新名字')self.assertEqual('新名字', student.name)service.find_name_by_id.assert_called()service.save_student.assert_called()def test_change_name_without_record(self):service.find_name_by_id = Mock()service.find_name_by_id.return_value = Noneservice.save_student = Mock()chang_name(1, '新名字')# 断言没有被调用service.save_student.assert_not_called()
patch
path可以临时用Mock对象替换一个目标(函数,方法,类)。本质还是上一节的Mock操作。
path可以替换的目标:
- 目标必须是可import的
- 是在使用的目标的地方替换而不是替换定义
path的使用方式:
- 装饰器的方式
- 上下文管理器的方式
- 手动方式
装饰器模拟(首选)
class Student:def __init__(self, id: int, name: str):self.id = idself.name = namedef find_name_by_id(id):passdef save_student(student):passdef chang_name(id: int, new_name: str):student = find_name_by_id(id)if student:student.name = new_namesave_student(student)
from unittest.mock import Mock, patch
from unittest import TestCase
from server.app import chang_nameclass TestService(TestCase):@patch("server.server.save_student")@patch("server.server.find_name_by_id")def test_change_name_decorator(self, find_name_by_id_mock, save_student_mock):student = Mock(id=1, name='旧名字')find_name_by_id_mock.return_value = studentchang_name(1, '新名字')self.assertEqual('新名字', student.name)find_name_by_id_mock.assert_called()save_student_mock.assert_called()
上下文管理器模拟
from unittest.mock import Mock, patch
from unittest import TestCase
from server.app import chang_nameclass TestService(TestCase):def test_change_name_context(self):student = Mock(id=1, name='旧名字')with patch("server.server.find_name_by_id") as find_name_by_id_mock, patch("server.server.save_student"):find_name_by_id_mock.return_value = studentchang_name(1, '新名字')self.assertEqual('新名字', student.name)
手动模拟
from unittest.mock import Mock, patch
from unittest import TestCase
from server.app import chang_nameclass TestService(TestCase):@patch("server.server.find_name_by_id")def test_change_name_manual(self, find_name_by_id_mock):student = Mock(id=1, name='旧名字')find_name_by_id_mock.return_value = studentpather = patch("server.server.save_student")pather.start()chang_name(1, '新名字')pather.start()self.assertEqual('新名字', student.name)
测试实例
path里面的模拟对象已经对所有魔术方法都进行了mock,如果不关心返回值可以不用后续return_value了
import os.path
from urllib.request import urlopen, Requestdef download_img(url: str):site_url = Request(url, headers={"User-Agent": "Mozilla/5.0"})with urlopen(site_url) as web_file:img_data = web_file.read()if not img_data:raise Exception(f"Error: cannot load the image from {url}")file_name = os.path.basename(url)with open(file_name, 'wb') as file:file.write(img_data)return f"Download image successfully, {file_name}"
from unittest.mock import patch, MagicMock
from unittest import TestCase
from server.app import download_img# https://www.bilibili.com/video/BV1EK411B7LX/?spm_id_from=333.788&vd_source=35b478ef20f153fb3c729ee792cdf651
class TestService(TestCase):# urlopen在方法参数中被mock为urlopen_mock# urlopen_mock的返回值是一个urlopen_result_mock# urlopen_result_mock的__enter__方法返回值是一个web_file_mock# web_file_mock的read方法返回值需要定义@patch("server.server.urlopen")# 因为在service.service文件中引入了,所以可以直接使用service.service引入Request@patch("server.server.Request.__new__")def test_download_img_with_exception(self, request_init_mock, urlopen_mock):# Setupurl = 'https://www.google.com/a.png'urlopen_result_mock = MagicMock()web_file_mock = MagicMock()urlopen_mock.return_value = urlopen_result_mockurlopen_result_mock.__enter__.return_value = web_file_mockweb_file_mock.read.return_value = Nonewith self.assertRaises(Exception):download_img(url)@patch("builtins.open")@patch("os.path.basename")@patch("server.server.urlopen")@patch("server.server.Request.__new__")def test_download_img_with_success(self, request_init_mock, urlopen_mock, basename_mock, open_mock):# Setupurl = 'https://www.google.com/a.png'urlopen_result_mock = MagicMock()web_file_mock = MagicMock()urlopen_mock.return_value = urlopen_result_mockurlopen_result_mock.__enter__.return_value = web_file_mockweb_file_mock.read.return_value = 'not none'basename_mock.return_value = 'fff'ret = download_img(url)self.assertEqual("Download image successfully, fff", ret)
测试覆盖率
#统计测试覆盖率
python -m coverage run -m unittest#查看覆盖率报告
python -m coverage report#生成html格式的覆盖率报告
python -m coverage html
pytest框架
起步
pytest是一个基于python语言的第三方测试框架。
有以下优点:
- 语法简单
- 自动检测测试代码
- 跳过指定测试
- 开源
安装使用
#安装
pip install pytest#运行(自动查找test_*.py,*_test.py测试文件。自动查找测试文件中test_开头的函数和Test开头的类中的test_开头的方法)
pytest
pytest -v#测试指定测试类
pytest test_xxx.py
常用参数
-v 输出详细的执行信息,比如文件和用例名称
-s 输出调试信息,比如print的打印信息
-x 遇到错误用例立即停止
跳过测试
@pytest.mark.skip
@pytest.mark.skipif
import sysfrom server.app import Student
import pytestdef skip():return sys.platform.casefold() == 'win32'.casefold()# @pytest.mark.skip(reason="暂时跳过")
@pytest.mark.skipif(condition=skip(), reason="window平台跳过")
class TestStudent:def test_student_create(self):student = Student(1, 'bob')assert student.id == 1assert student.name == 'bob'def test_student_create():student = Student(2, 'alice')assert student.id == 2assert student.name == 'alice'
@pytest.fixture
class Student():def __init__(self, id: int, name: str):self.id = idself.name = namedef valid_name(self):if self.name:return 3 < len(self.name) < 10return False
from server.app import Student
import pytest@pytest.fixture
def valid_student():student = Student(1, 'Kite')yield student@pytest.fixture
def not_valid_student1():student = Student(2, 'abcdefjijklmnopq')yield student@pytest.fixture
def not_valid_student2(not_valid_student1):# 这里不能对valid_student的name进行赋值修改哟student = Student(3, 'Bob')student.name = not_valid_student1.nameyield studentdef test_student(valid_student, not_valid_student1, not_valid_student2):ret = valid_student.valid_name()assert retret = not_valid_student1.valid_name()assert not retret = not_valid_student2.valid_name()assert not ret
conftest.py
作用:使得fixture可以被多个文件中的测试用例复用。
在tests目录下建立conftest.py文件,这里引入其他文件中的fixture,那么其他用例中就可以使用这些fixture,你也可以定义fixture在这个文件中(但是不推荐哈)
参数化测试
# 判断是否是奇数
def is_odd(x: int):return x % 2 != 0
import pytestfrom server.app import is_odd@pytest.mark.parametrize("num,expect_ret", [(1, True), (2, False)])
def test_is_odd(num, expect_ret):actual_ret = is_odd(num)assert expect_ret == actual_ret
数据库查询的mock
import pytest
from unittest.mock import patch, MagicMock
from server.controller.message_controller import create_user@pytest.fixture
def mock_session_scope():with patch("server.db.session.session_scope") as mock_session_scope:mock_session_scope_return_value = MagicMock()mock_session_scope.return_value = mock_session_scope_return_valuesession_mock = MagicMock()mock_session_scope_return_value.__enter__.return_value = session_mockyield session_mockdef test_create_user(mock_session_scope):ret = create_user("alice")assert 'ok' == retdef test_create_user_exception(mock_session_scope):with pytest.raises(ValueError):create_user("")
覆盖率
pip install pytest
pip install pytest-cov
pytest --cov --cov-report=html
相关文章:
python单元测试
文章目录 单元测试定义断言函数Test FixturesMockpatch装饰器模拟(首选)上下文管理器模拟手动模拟 测试实例 测试覆盖率pytest框架起步安装使用常用参数跳过测试pytest.fixtureconftest.py参数化测试 数据库查询的mock覆盖率 单元测试 定义 单元测试是…...
华为---静态路由-浮动静态路由及负载均衡(二)
7.2 浮动静态路由及负载均衡 7.2.1 原理概述 浮动静态路由(Floating Static Route)是一种特殊的静态路由,通过配置去往相同的目的网段,但优先级不同的静态路由,以保证在网络中优先级较高的路由,即主路由失效的情况下,…...
Maven deploy上传远程私服失败
Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy (default-deploy) on project 你的项目: Cannot deploy artifacts when Maven is in offline mode 解决方案: 1.IDEA把这个钩子去掉 2. settings.xml里把 <offline>标…...
通天星CMSV6车载定位监控平台 point_manage/merge SQL注入致RCE漏洞复现
0x01 产品简介 通天星CMSV6车载定位监控平台拥有以位置服务、无线3G/4G视频传输、云存储服务为核心的研发团队,专注于为定位、无线视频终端产品提供平台服务,通天星CMSV6产品覆盖车载录像机、单兵录像机、网络监控摄像机、行驶记录仪等产品的视频综合平台。 0x02 漏洞概述 …...
图像识别技术在人脸识别领域的新突破
图像识别技术在人脸识别领域的新突破主要体现在多个方面,这些突破不仅提高了人脸识别的准确性和效率,还拓展了其应用领域。以下是对这些新突破的详细归纳: 深度学习技术的应用: 深度学习技术,特别是卷积神经网络&…...
iview 组件里面的(任何一个月)整月日期全部选中_iview时间轴选中有历史记录日期
iview 组件里面的整月日期全部选中: ①:第一种是当前月的日期全部选中: 先上效果图:当前月分 获取到的值: 当前月的方法: // getDateStr() {// var curDate new Date();// var curMonth curDate.ge…...
Charles配置与API数据抓取
2024软件测试面试刷题,这个小程序(永久刷题),靠它快速找到工作了!(刷题APP的天花板)-CSDN博客跳槽涨薪的朋友们有福了,今天给大家推荐一个软件测试面试的刷题小程序。https://blog.c…...
[FreeRTOS 内部实现] 信号量
文章目录 基础知识创建信号量获取信号量释放信号量信号量 内部实现框图 基础知识 [FreeRTOS 基础知识] 信号量 概念 创建信号量 #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) #define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) #define xSe…...
Vue57-组件的自定义事件_解绑
给谁绑的自定义事件,就找谁去触发;给谁绑的自定义事件,就找谁去解绑; 一、解绑自定义事件 1-1、解绑一个自定义事件 到student.vue组件中去解绑。 1-2、解绑多个自定义事件 使用数组来解绑多个。 1-3、解绑所有的自定义事件 二、…...
Java启动jar设置内存分配详解
在微服务架构越来越盛行的情况下,我们通常一个系统都会拆成很多个小的服务,但是最终部署的时候又因为没有那么多服务器只能把多个服务部署在同一台服务器上,这个时候问题就来了,服务器内存不够,这个时候我们就需要对每…...
Feign Client超时时间设置不生效问题
在使用Feign Client时,可以通过两种方式来设置超时时间: 针对整个Feign Client设置超时时间 可以在Feign Client的配置类中通过修改Request.Options对象来设置超时时间。Request.Options对象有两个属性,connectTimeoutMillis用于设置连接超…...
Haproxy部署Web群集
概论 HAProxy是可提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,是免费、快速并且可靠的一种解决方案。HAProxy非常适用于并发大(并发达1w以上)web站点,这些站点通常又需要会话保持或七层处理。HAProxy的运行模式使得它可以…...
C++STL梳理
CSTL标准手册: https://cplusplus.com/reference/stl/ https://cplusplus.com/reference/vector/vector/at/ 1、STL基础 1.1、STL基本组成(6大组件13个头文件) 通常认为,STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成&…...
找出1000以内的所有的完数
完数的概念:完数(Perfect Number)是一个正整数,它等于除了它本身以外所有正因子之和。例如,6的因子有1、2、3和6,其中1236,所以6是一个完数。 #include <stdio.h> // 函数用于计算一个数…...
3110. 字符串的分数
给你一个字符串 s 。一个字符串的 分数 定义为相邻字符 ASCII 码差值绝对值的和。 请你返回 s 的 分数 。 示例 1: 输入:s "hello" 输出:13 解释: s 中字符的 ASCII 码分别为:h 104 ,e 1…...
Mybatis MySQL allowMultiQueries 一次性执行多条语句
在JDBC 增加参数allowMultiQueries jdbc:mysql://localhost:3306/abc?&allowMultiQueriestrue <insert id"addRi" parameterType"java.util.List">DELETE FROM sys_ri WHERE sr_id #{roId} AND sr_fion_id #{fod};INSERT into sys_rVALUES&…...
Kubernates容器化JVM调优笔记(内存篇)
Kubernates容器化JVM调优笔记(内存篇) 先说结论背景思路方案 先说结论 1、首先如果是JDK8,需要使用JDK8_191版本以上,才支持容器化环境和以下参数,否则就更新到JDK10以上,选择对应的镜像构建就行了 2、在容…...
Elasticsearch Scroll 报错entity content is too long
2024-06-24 15:22:01:568 ERROR [task-31] (ScrollFetcherProduceAction.java:129) 访问ES出错org.apache.http.ContentTooLongException: entity content is too long [112750110] for the configured buffer limit [104857600]at org.elasticsearch.client.HeapBufferedAsync…...
Vue iview输入框change事件replace正则替换不生效问题的解决。
// 需求:输入座机号只允许输入数字和"-" onChange(e){this.$nextTick(()>{this.phone e.target.value.replace(/[^0-9-]/g, );}) } 解决:添加**this.$nextTick**即可...
Prestashop跨境电商独立站,外贸B2C网站完整教程
Prestashop是一款来自法国专业的开源电商CMS(内容管理系统)平台,和wordpress一样比较轻量,适合中小网站。Prestashop跨境电商独立站在国内并不是很流行,不过国外是非常火的,从各大平台的Prestashop主题数量就可以看得出来。 最有…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
