用pytest测试python:夹具和覆盖率
off999 2024-10-01 14:01 18 浏览 0 评论
改善你的python测试
在我最近的两篇文章中,我介绍了pytest,一个用来测试python代码的library(详见《用python的pytest测试你的代码》第一部分和第二部分),Pytest已经非常流行,在很大程度上是因为它非常容易编写测试并将这些测试集成到软件开发程序中。我已经成为了它的铁杆粉丝,主要是因为多年来我一直在说我应该更好地测试我的软件,Pytest最终使它成为可能。
所以在本文中,我回顾了Pytest的两个特性,在之前还没有机会介绍它们:fixture和code coverage,这将(我希望)让你相信Pytest是值得探索和进入到您的工作中的。
夹具:
当你写测试的时候,很少只写一两个。相反,你会写一个完整的“测试套件”,每个测试的目标是通过代码检查不同的路径。通常这意味着你将有一些具有类似特性的测试,这些pytest可以用“参数化测试”处理。
但在其他情况下,情况会更复杂一些。您会想让对象适用于所有的测试。这些对象可能包含要在测试之间共享的数据,或者它们可能涉及网络或文件系统。在测试世界中,这些通常被称为“夹具”,它们采用各种不同的形式。
在Pytest中,可以使用Pytest.fixture装饰器和函数定义的组合来定义fixture。例如,假设您有一个文件,该文件返回一个文件中的行列表,其中每一行都是相反的:
请注意,为了避免换行符放在行首,请在反转之前将其从字符串中删除,然后在每个返回的字符串中添加一个" "。另外需要注意的是,虽然用生成器表达式而不是列表理解可能是个更好的想法,但我在这里只是想让事情相对简单一点。
如果您要测试这个函数,您需要将它传递给一个类似文件的对象。在我上一篇文章中,我展示了如何使用Stringio对象来处理这样的事情,这种情况依旧可以这样。但是,您不必在测试文件中定义全局变量,而是可以创建一个夹具,在适当的时间为您的测试提供适当的对象。
下面看看Pytest是如何处理的:
从表面上看,这看起来像是一个简单的函数,它返回你稍后要用的值。在许多方面它与你用“简单文件”的名称定义全局变量所得到的类似。
同时,夹具的使用与全局变量不同。例如,如果你想让你的一个测试中包含这个夹具。您可以在测试的参数列表中声明它。然后在测试中就可以通过名称访问fixture。例如:
但它会变得更好。你的fixture可能像数据一样,因为你不必使用括号来调用它。但它实际上是一个钩子下的函数,这意味着它在每次引用该夹具调用测试时都会执行。说明与常规的旧数据相比,夹具可以进行计算和决策。
您还可以决定设备运行的频率。例如,正如现在写的,这个fixture将在提到它的每个测试中运行一次。在你想与列表或类似文件的结构进行比较的情况中,这非常好。但是如果你想设置一个对象,然后多次使用它而不重新创建它,该怎么办?您可以通过设置夹具的“范围”来实现这一点。例如,如果将fixture的范围设置为“module”,那么它将在整个测试过程中可用,但只执行一次。可以通过将scope参数传递给@pytest.fixture 装饰器来完成此操作:
我应该说明给这个特定的fixture“module”范围是一个坏主意, 因为第二个测试将会得到一个StringIO,它的位置指针(用file.tell测试)已经在末尾了。
这些夹具的工作方式与许多其他测试系统使用的传统安装/拆卸系统截然不同。但是,Pytest的人肯定让我相信这是一种更好的方法。
但是等等,也许您可以看到这些设备中的“设置”功能在哪里。“拆卸”功能在哪里?答案既简单又优雅。如果您的fixture使用“yield”而不是“return”,那么pytest就会知道post-yield代码用于分解对象和连接。是的,如果您的夹具具有“模块”范围,那么pytest将等到范围中的所有功能都完成执行后再将其拆下。
覆盖率
这一切都很棒,但是如果您曾经做过任何测试,那么您知道总是有一个问题,即您对代码的测试有多彻底。毕竟,假设您已经编写了五个函数,并且已经为所有函数编写了测试。你能确定通过这些函数你已经测试了所有的可能路径吗?
例如,假设您有一个非常奇怪的函数,only_odd_mul,它只乘奇数:
这是一个你可以运行该函数的测试
当然,测试通过了。它很管用!软件太棒了!
哦,但是你可能已经注意到了,那不是一个很好的测试工作。有一些方法可以让函数给出一个完全不同的结果(例如,引发一个异常),而测试没有检查这个结果。
也许在这个例子中很容易找到它,但是当软件变得越来越大、越来越复杂时,就不那么容易看到它了。在您想要“代码覆盖率”的地方,检查您的测试是否运行了所有代码。
现在,100%的代码覆盖率并不意味着您的代码是完美的或者它没有漏洞。但它确实让您对代码有更大的信心,而且它至少运行过一次。
那么,如何在pytest中包含代码覆盖率呢?答案是PyPI上有一个名为pytest-cov的包,您可以下载并安装它。完成后,可以使用--cov选项调用pytest。如果你不再说其他的话,你将得到你的程序使用的python库的每个部分的覆盖率报告,因此我强烈建议您提供一个参数—cov来指定要测试的程序。并且,您应该指出报告应该写入的目录。在这种情况下,你会说:
一旦你做到了这一点,你就需要把覆盖率报告转化为人类可读的东西。我建议使用HTML,尽管其他输出格式也是可以用的:
这将创建一个名为htmlcov的根目录。使用浏览器打开这个目录中的index.html文件,您将得到一个基于Web的报告,其中显示(红色)您的程序仍然没有覆盖范围。当然,在本例中,它显示偶数路径没有被覆盖。让我们添加一个测试来执行此操作
正如预期的那样,覆盖率现在已经上升到100%!这绝对是值得赞赏和庆祝的,但并不意味着你已经达到了最佳测试。你可以也应该考虑不同的混合论点,以及当你通过它们时会发生什么。
总结
如果你还没有从我关于Pytest的第三部分猜到,我已经被这个测试系统的设计方式所折服了。在谈到测试时羞愧地绞尽脑汁数年之后,我开始将它融入到我的代码中,包括在我的在线“每周Python练习”课程中。如果我能参加测试,你也能。虽然我还没有尝试pytest提供的所有内容,但是您现在应该对它是什么以及如何开始使用它有了很好的了解。
资源
Pytest网站:http://pytest.org。
关于这个主题的有一本很棒的书是Brian Okken的用pytest测试python,由Pragmatic Programmers出版。他还有很多其他关于pytest和一般的代码测试的资源,请访问http://pythontesting.net。
布赖恩关于Pytest装置的博客文章对任何想开始使用它们的人都是有益和有价值的。
英文原文:https://www.linuxjournal.com/content/python-testing-pytest-fixtures-and-coverage
译者:游骑兵
相关推荐
- Python钩子函数实现事件驱动系统(created钩子函数)
-
钩子函数(HookFunction)是现代软件开发中一个重要的设计模式,它允许开发者在特定事件发生时自动执行预定义的代码。在Python生态系统中,钩子函数广泛应用于框架开发、插件系统、事件处理和中...
- Python函数(python函数题库及答案)
-
定义和基本内容def函数名(传入参数):函数体return返回值注意:参数、返回值如果不需要,可以省略。函数必须先定义后使用。参数之间使用逗号进行分割,传入的时候,按照顺序传入...
- Python技能:Pathlib面向对象操作路径,比os.path更现代!
-
在Python编程中,文件和目录的操作是日常中不可或缺的一部分。虽然,这么久以来,钢铁老豆也还是习惯性地使用os、shutil模块的函数式API,这两个模块虽然功能强大,但在某些情况下还是显得笨重,不...
- 使用Python实现智能物流系统优化与路径规划
-
阅读文章前辛苦您点下“关注”,方便讨论和分享,为了回馈您的支持,我将每日更新优质内容。在现代物流系统中,优化运输路径和提高配送效率是至关重要的。本文将介绍如何使用Python实现智能物流系统的优化与路...
- Python if 语句的系统化学习路径(python里的if语句案例)
-
以下是针对Pythonif语句的系统化学习路径,从零基础到灵活应用分为4个阶段,包含具体练习项目和避坑指南:一、基础认知阶段(1-2天)目标:理解条件判断的逻辑本质核心语法结构if条件:...
- [Python] FastAPI基础:Path路径参数用法解析与实例
-
查询query参数(上一篇)路径path参数(本篇)请求体body参数(下一篇)请求头header参数本篇项目目录结构:1.路径参数路径参数是URL地址的一部分,是必填的。路径参...
- Python小案例55- os模块执行文件路径
-
在Python中,我们可以使用os模块来执行文件路径操作。os模块提供了许多函数,用于处理文件和目录路径。获取当前工作目录(CurrentWorkingDirectory,CWD):使用os....
- python:os.path - 常用路径操作模块
-
应该是所有程序都需要用到的路径操作,不废话,直接开始以下是常用总结,当你想做路径相关时,首先应该想到的是这个模块,并知道这个模块有哪些主要功能,获取、分割、拼接、判断、获取文件属性。1、路径获取2、路...
- 原来如此:Python居然有6种模块路径搜索方式
-
点赞、收藏、加关注,下次找我不迷路当我们使用import语句导入模块时,Python是怎么找到这些模块的呢?今天我就带大家深入了解Python的6种模块路径搜索方式。一、Python模块...
- 每天10分钟,python进阶(25)(python进阶视频)
-
首先明确学习目标,今天的目标是继续python中实例开发项目--飞机大战今天任务进行面向对象版的飞机大战开发--游戏代码整编目标:完善整串代码,提供完整游戏代码历时25天,首先要看成品,坚持才有收获i...
- python 打地鼠小游戏(打地鼠python程序设计说明)
-
给大家分享一段AI自动生成的代码(在这个游戏中,玩家需要在有限时间内打中尽可能多的出现在地图上的地鼠),由于我现在用的这个电脑没有安装sublime或pycharm等工具,所以还没有测试,有兴趣的朋友...
- python线程之十:线程 threading 最终总结
-
小伙伴们,到今天threading模块彻底讲完。现在全面总结threading模块1、threading模块有自己的方法详细点击【threading模块的方法】threading模块:较低级...
- Python信号处理实战:使用signal模块响应系统事件
-
信号是操作系统用来通知进程发生了某个事件的一种异步通信方式。在Python中,标准库的signal模块提供了处理这些系统信号的机制。信号通常由外部事件触发,例如用户按下Ctrl+C、子进程终止或系统资...
- Python多线程:让程序 “多线作战” 的秘密武器
-
一、什么是多线程?在日常生活中,我们可以一边听音乐一边浏览新闻,这就是“多任务处理”。在Python编程里,多线程同样允许程序同时执行多个任务,从而提升程序的执行效率和响应速度。不过,Python...
- 用python写游戏之200行代码写个数字华容道
-
今天来分析一个益智游戏,数字华容道。当初对这个游戏颇有印象还是在最强大脑节目上面,何猷君以几十秒就完成了这个游戏。前几天写2048的时候,又想起了这个游戏,想着来研究一下。游戏玩法用尽量少的步数,尽量...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python自定义函数 (53)
- python进度条 (67)
- python吧 (67)
- python字典遍历 (54)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python串口编程 (60)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python字典增加键值对 (53)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python人脸识别 (54)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)