快速入门
创建第一个测试
创建一个名为 test_sample.py
的新文件,其中包含一个函数和一个测试:
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
测试输出:
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 1 item
test_sample.py F [100%]
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================
[100%]
指的是运行所有测试用例的总体进度。在所有测试用例执行完毕后,pytest会显示一个失败报告,因为 func(3)
没有返回 5
。
您可以使用
assert
语句来验证测试的期望结果。pytest的高级断言内省功能会智能地报告assert
表达式的中间值,以便您避免使用JUnit遗留方法的许多名称。
运行多个测试案例
pytest
将运行当前目录及其子目录中所有形如 [test]().py
或 *_test.py
的文件。它遵循标准的测试发现规则。
断言抛出了指定异常
使用raise
可以在相应代码的抛出的指定异常:
# content of test_sysexit.py
import pytest
def f():
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
使用“静默”模式,执行这个测试用例如:
$ pytest -q test_sysexit.py
. [100%]
1 passed in 0.12s
在这个例子和后续例子中,
-q/--quiet
标志可使输出保持简洁。
使用类组织多条测试用例
一旦你需要开发多条测试用例,你可能会想要使用类来组织它们。使用Pytest可以很轻松的创建包含多条用例的测试类:
# 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
遵循其Python测试发现规则来查找所有测试,因此它会找到以 test_
为前缀的函数。不需要继承任何东西,但确保将类名以 Test
为前缀,否则该类将被跳过。我们只需通过传递模块的文件名来运行模块:
$ pytest -q test_class.py
.F [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0xdeadbeef0001>
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
第一条用例执行成功,第二天用例执行失败。你可以很容易地通过断言中变量的中间值来理解失败的原因。
将测试用例分组在类中可以有以下几个好处:
- 测试组织
- 仅在特定类中共享测试用例的测试夹具(fixtures)
- 在类级别应用标记,并使其隐式应用于所有测试用例
需要注意的是,将测试用例分组在类中时,每个测试用例都有一个独立的类实例。如果每个测试用例共享相同的类实例,将会严重影响测试隔离性,并促使不良的测试实践。以下是详细说明:
# content of test_class_demo.py
class TestClassDemoInstance:
value = 0
def test_one(self):
self.value = 1
assert self.value == 1
def test_two(self):
assert self.value == 1
$ pytest -k TestClassDemoInstance -q
.F [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_two ______________________
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>
def test_two(self):
> assert self.value == 1
E assert 0 == 1
E + where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value
test_class_demo.py:9: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
1 failed, 1 passed in 0.12s
请注意,添加在类级别的属性是 类属性,因此它们将在测试用例之间共享。
为功能测试请求一个独立的临时目录
pytest
提供了内置的 fixture 函数参数,用于请求任意资源,比如一个独立的临时目录:
# content of test_tmp_path.py
def test_needsfiles(tmp_path):
print(tmp_path)
assert 0
在测试函数的签名中列出 tmp_path
,pytest
会查找并调用一个 fixture 工厂来在执行测试函数之前创建资源。在测试运行之前,pytest
会创建一个独立的、每次测试调用都不同的临时目录。
$ pytest -q test_tmp_path.py
F [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')
def test_needsfiles(tmp_path):
print(tmp_path)
> assert 0
E assert 0
test_tmp_path.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_needsfiles - assert 0
1 failed in 0.12s
有关临时目录处理的更多信息,请参阅临时目录和文件。
使用以下命令查找存在的内置 pytest fixture
类型:
pytest --fixtures # shows builtin and custom fixtures
请注意,该命令将忽略以 _
开头的 fixture,除非添加 -v
选项。
继续阅读
- 使用 "
usage
" 获取命令行调用示例。 - 使用 "
existingtestsuite
" 处理现有测试。 - 查阅 "
mark
" 以深入了解pytest.mark
机制。 - 学习 "
fixtures
" 为您的测试提供功能基线。 - 探索 "
plugins
" 来管理和编写插件。 - 参考 "
goodpractices
" 以了解 virtualenv 和测试布局的最佳实践。