pytest
在工程和实践应用中,常常会遇到我们需要进行测试的地方。而pytest是一种非常方便易用的针对小型测试的工具。
详细信息可以参考官方文档
1. 安装
可以直接使用pip
安装,输入如下命令:
pip install -U pytest
可以通过如下命令查看对应的版本号:
pytest --version
2 编写一个测试
使用pytest,实质上是搜索目录下对应的文件,并且执行和查看是否出现错误。如下是一个简单的示例:
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5 # 该测试会失败,func(3)应该为4
编写该程序后,在该目录下命令行中输入:
pytest ./test_sample.py
然后会检测断言assert
的内容的真假,并显示出对应的信息:
========================================== test session starts ==========================================
platform win32 -- Python 3.7.7, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: C:\Users\dell\Desktop\TEST\py_tmp
collected 1 item
test_sample.py F [100%]
=============================================== FAILURES ================================================
______________________________________________ test_answer ______________________________________________
def test_answer():
> assert func(3) == 5 # 该测试会失败,func(3)应该为4
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
======================================== short test summary info ========================================
FAILED test_sample.py::test_answer - assert 4 == 5
=========================================== 1 failed in 0.04s ===========================================
其中[100%]指所有测试案例的全部进行了测试。测试完成后,pytest将显示失败报告,因为func(3)并不会返回5而是4。
3. pytest约定
pytest会测试当前目录下所有形如 *_test.py
和test_*.py
的文件。
在这些文件中,会执行所有带test
前缀的方法或者是函数。其中如果时类方法则需要类以Test
开头且没有__init__()
方法。
4. 将测试分类
可以使用类来区分不同的测试,例如:
# content of test_class.py
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
此时pytest会测试Test类中的两个测试。可以使用命令参数-q
(-quite
)表示简化输出。该测试将会通过一个失败一个。具体结果为:
pytest -q test_class.py
.F [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0xdeadbeef>
def test_two(self):
x = "hello"
> assert hasattr(x, "check")
E AssertionError: assert False
E + where False = hasattr('hello', 'check')
test_class.py:8: AssertionError
========================= short test summary info ==========================
FAILED test_class.py::TestClass::test_two - AssertionError: assert False
1 failed, 1 passed in 0.12s
当一个文件中有多个测试类的时候,如下:
# content of test_class2.py
class TestClassOne(object):
def test_one(self):
x = "this"
assert 't'in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
class TestClassTwo(object):
def test_one(self):
x = "iphone"
assert 'p'in x
def test_two(self):
x = "apple"
assert hasattr(x, 'check')
可以使用命令指定测试某个类内的测试:
仅执行TestClassOne
中的两个测试可以使用命令:
pytest test_class2.py::TestClassOne
仅仅执行TestClassOne
中的测试test_one
可以使用命令:
pytest test_class2.py::TestClassOne::testone
5. 显示print信息
在进行测试的时候,可能会在代码中添加print
语句,产生一些信息。可以使用参数-s
来在运行pytest
的时候输出这些信息:
pytest test_se.py -s
6. 多进程运行测试
当测试的数目很大的时候,运行时间会比较长。此时可以采用多进程来进行测试。需要先下载安装pytest-xdist
:
pip install -U pytest-xdist
在使用pytest时,指定参数-n num
即可,其中num
为进程数:
pytest test_*.py -n num
7. 重试运行测试
有时候可能由于其他原因导致测试失败,需要重试多次运行某个测试。需要下载安装pytest-rerunfailures
:
pip install -U pytest-rerunfailures
在使用pytest的时候,指定参数--reruns num
,其中num
为重试次数:
pytest test_*.py -reruns num
8. 断言
8.1 断言
assert
用于判断一个表达式,在表达式条件为 False
的时候触发异常。其语法格式为:
assert Expression
等价于
if not expression:
raise AssertionError
assert
后面也可以紧跟参数来出发对应的错误类型。同样会在使用pytest
中的错误信息中对应地显示出来。
assert expression [, arguments]
8.2 断言几乎相等
在使用断言的时候,浮点数不能直接使用断言来进行判断,其结果一般都会是失败。原因在于浮点数的截断情况导致会比实际值略有一定的偏差。
几种常见的写法是:
assert x - esp <= y <= x + esp # esp = 1e-6
assert abs(x-y) < esp # esp = 1e-6
但是对于数组、元组、字典等,需要将数据提取出来在进行比较。实际上我们可以使用pytest.approx
来断言几乎相等,示例如下:
assert 2.2 == pytest.approx(2.3)
# 失败,默认允许2.3e-6的误差
assert 2.2 == pytest.approx(2.3, 0.1)
# 成功,指定误差是0.1
assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx([0.3, 0.6])
# 成功,适用于断言一维数组
assert {
'a': 0.1+0.2} == pytest.approx({
'a': 0.3})
# 成功,适用于断言字典
assert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]])
# 失败,目前pytest不支持多维数组等类型
实际上我们还可以使用numpy.testing
来协助比较,详细可以参考它的文档。