社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用pytest测试python:夹具和覆盖率

Python程序员 • 5 年前 • 470 次点击  


改善你的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
译者:游骑兵



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/7UyR5UeOzP
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/28026
 
470 次点击