在 PyCharm 里使用 Pytest 测试框架
在上一小节已经介绍了基于 Python unittest 在 PyCharm 里执行测试相关知识,本节将继续介绍另一个比较流行的测试框架 Pytest。
1. Pytest 介绍
Pytest 是 Python 语言中一款强大的单元测试框架,它是基于 unittest 开发的扩展框架,用来管理和组织测试用例,可应用在单元测试、自动化测试工作中。
Pytest 主要特点:
1. 兼容性好: 支持 Python 2.7,Python 3.4+。
2. 与 unittest 和 nose 测试框架兼容: 如果之前测试用例全部是基于 unittest 或者 nose 来编写的,执行 Pytest 命令同样可以正常运行并得到结果。因此无需担心迁移测框架从而带来额外的人工成本。
3. 丰富的插件支持: 大约有 300 多个,像 Pytest-repeat, pytest-xdist,pytest-ordering,pytest-rerunfailures 以及 pytest-html 这些常用插件在测试重复执行、并发与生成报告方面都提供了非常强大的支持。
4. 允许直接使用 assert 进行断言:相比 unittest 简单,unittest 定义了 assertEqual、assertIn、assertTrue、assertFalse 等一系列断言。
5. 可以自动寻找单测文件、类和函数:Pytest 要求所有的单测文件名都需要满足 test_.py 格式或_test.py 格式。在单测文件中,可以包含 test_ 开头的函数,也可以包含 Test 开头的类。在单测类中,可以包含一个或多个 test_ 开头的函数。在执行 Pytest 命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行。
6. 提供应用不同范围前置/后置方法: Pytest 提供了模块级、函数级、类级、方法级的setup/teardown,比 unittest 的 setUp/tearDown 更灵活。
7. 分类执行与测试数据参数化简单 : unittest 需依赖 ddt 库实现数据参数化,而 Pytest 直接使用@pytest.mark.parametrize 装饰器。
总之, Pytest 因为其功能强大性及使用的方便性,已经成为主流的测试框架之一,unittest 更适合入门级的测试,当执行比较复杂的测试 Pytest 就更适合一些,这也是为什么我们会单列一小节讲 Pytest 的原因。更多关于 Pytest 使用请参考官网。
2. 使用 Pytest 执行测试
在 PyCharm 里使用 Pytest 执行测试的过程与 unittest 是一致的,所以对于步骤上的操作在本小节将不再过多说明,将把重点关注在 Pytest 一些特性上。
2.1 配置测试框架
主菜单: PyCharm/File -> Preference/Settings -> Tools -> Python Integrated Tools
, 点击 Default Test Runner 选择 Pytest。
2.2 创建测试
创建一个新的 Python project,增加新文件 rectangle.py,添加下面的代码到文件, 继续沿用上一小节用到的待测代码。
import math
class Rectangle:
def __init__(self, length, width, size=(40, 20)):
self.length = length
self.width = width
self._size = size
def area(self):
area = self.length * self.width
return area
def perimeter(self):
perimeter = (self.length + self.width) * 2
return perimeter
def diff(self):
diff = math.fabs(self.length - self.width)
return diff
def resize(self, width, height):
if width <= 0 or height <= 0:
raise ValueError("illegal size")
self._size = (width, height)
def get_length(self):
return self.length
def get_width(self):
return self. width
在编辑器中,将光标放在类声明或方法中的位置。
- 从主菜单中,选择
Navigate -> Test
。 - 编辑器内,右键上下文菜单中选择
Go to -> Test (⌘⇧T: Ctrl + Shift + T)
PyCharm 显示可用测试的列表。单击"创建新测试"。在打开 Create test 对话框中进行设置, 点击 OK 会自动生成测试文件 test_rectangle 与 测试方法模板。
生成的模板 如下图所示: 没有像 unittest 那样创建同名测试类,无需像导入 unittest 一样导入pytest , 断言直接用 assert。使用pytest 写测试用例看上去更简单一些。
2.3 修改代码与执行测试
根据 Pytest 规则更新代码:
from rectangle import Rectangle
def test_area():
rect = Rectangle(30, 15)
assert rect.area() == 450
def test_perimeter():
rect = Rectangle(30, 15)
assert rect.perimeter() == 90
在 编辑器的上下文菜单,选择 Run pytest for Name,会默认运行当前文件所有以 ‘test’ 开头的所有方法。Run 窗口会自动弹出,显示测试结果。
3. Pytest 一些特性
从上面介绍可以看出,无论用哪种测试框架,基本流程都是一样的。下面介绍一些Pytest 一些特性,这些特性都是使用频率比较高,也是相对于unittest 测试功能更为便利与先进的功能。
3.1 使用 fixture
fixture 是 Pytest 特有的功能,它用 pytest.fixture 标识,定义在函数前面。在你编写测试函数的时候,你可以将此函数名称做为传入参数,pytest将会以依赖注入方式,将该函数的返回值作为测试函数的传入参数。
我们可以把fixture看做是资源,在你的测试用例执行之前需要去配置这些资源,执行完后需要去释放资源。比如module类型的fixture,适合于那些许多测试用例都只需要执行一次的操作。更多使用请参考这里
上面的两个测试方法都有 rect = Rectangle(30, 15)
实例化类, 此时可以使用 fixture 简化代码:
from rectangle import Rectangle
import pytest
@pytest.fixture()
def my_rect():
rect = Rectangle(30, 15)
return rect
def test_area(my_rect):
assert my_rect.area() == 450
def test_perimeter(my_rect):
assert my_rect.perimeter() == 90
3.2 标记用例
pytest.mark 定义在函数前面。可以给用例打标签,用于给用例分类与筛选用例。每个用例可以加多个标签。在执行用例时根据标签名选择执行。相比unittest 通过 TestSuite 加载不同的测试用例要方便的多。
from rectangle import Rectangle
import pytest
@pytest.fixture()
def my_rect():
rect = Rectangle(30, 15)
return rect
@pytest.mark.smoke
@pytest.mark.p1
def test_area(my_rect):
assert my_rect.area() == 450
@pytest.mark.regression
def test_perimeter(my_rect):
assert my_rect.perimeter() == 90
在运行之前, 需要先创建一个pytest.ini 文件在当前项目下,注册标签名。
[pytest]
markers=
smoke
p1
regression
运行的时候加参数 -m 标签名, 就可以只执行带标签名的用例。
3.3 测试数据参数化
你可能希望在预定义的数据集上运行测试。PyCharm 支持通过 @pytest.mark.parametrize 在 pytest 中实现的测试参数化。更多使用参考
增加下面的测试用例在 test_rectangle.py 文件中,传递三个参数两组数据给测试用例。如果数据可以用于其它用例,也可以定义数据做为全局变量。
@pytest.mark.parametrize(("length", "width", "expected_diff"), [(30, 20, 10), (20, 20, 0)])
def test_diff(length, width, expected_diff):
rect = Rectangle(length, width)
assert rect.diff() == expected_diff
点击编辑器侧边框绿色箭头执行上面的用例,可以看到用例执行了两次:
3.4 重复运行用例
有时候需要重复运行单个用例,Pytest也提供相应的插件支持 。需要事先安装包 pytest-repeat, Preference/Settings -> Project -> Python Interpreter
通过在函数前加 @pytest.mark.repeat(次数),指定函数重复的次数,也可以通过命令行–count=次数,为所有函数级别方法指定重复次数。
@pytest.mark.regression
@pytest.mark.repeat(5)
def test_perimeter(my_rect):
assert my_rect.perimeter() == 90
执行测试用例,可以看到用例被执行了5 次:
3.5 并发执行用例
有时候为了节省测试时间,需要并发执行测试用例。Pytest 是支持并发测试的,需提前安装包 pytest-xdist。运行的时候加参数 -n 并发进程数 或者 -n auto (根据当前cpu信息自动分配合理的核数运行用例。也可以在 pytest.ini 指定。
[pytest]
addopts = -n3
为了增强演示效果,在三个用例里都增加了10秒的延迟,并设置了三个并发,可以观察到三个用例是同时执行的。
Tips:当使用这个插件做并发测试时,只能用于没有依赖关系的测试用例。
4. 小结
本节主要介绍了在 PyCharm 里如何使用 Pytest 测试框架和一些测试过程中常用插件。Pytest 是功能非常强大的测试框架,在业内也比较被推崇,如果想真正掌握,建议多参考官方文档及相关的插件说明文档,这将帮助我们在开发单元测试与自动化测试过程中事半功倍。