pytest的开发者在pytest中包含了一些常用的Fixture。pytest预包装的Fixture可以帮助你在测试中轻松而一致地做一些非常有用的事情。例如pytest包含的内置Fixture可以处理临时目录和文件,访问命令行选项,在测试会话之间通信,验证输出流,修改环境变量,以及询问警告。内置固定程序是对pytest的核心功能的扩展。
tmp_path和tmp_path_factory
tmp_path 和 tmp_path_factory Fixture用于创建临时目录。tmp_path返回一个pathlib.Path实例,该实例指向一个临时目录,在你的测试期间和更长的时间内一直存在。tmp_path_factory session-scope fixture返回一个TempPathFactory对象。这个对象有一个mktemp()函数来返回Path对象。你可以使用mktemp()来创建多个临时目录。
ch4/test_tmp.py
def test_tmp_path(tmp_path):
file = tmp_path / "file.txt"
file.write_text("Hello")
assert file.read_text() == "Hello"
def test_tmp_path_factory(tmp_path_factory):
path = tmp_path_factory.mktemp("sub")
file = path / "file.txt"
file.write_text("Hello")
assert file.read_text() == "Hello"
使用tmp_path_factory,你必须调用mktemp()来获得一个目录。tmp_path_factory是session 范围。tmp_path是function 范围。
在上一章中,我们使用标准库中的tempfile.TemporaryDirectory作为我们的db夹具。
import cards
import pytest
@pytest.fixture(scope="session")
def db(tmp_path_factory):
"""CardsDB object connected to a temporary database"""
db_path = tmp_path_factory.mktemp("cards_db")
db_ = cards.CardsDB(db_path)
yield db_
db_.close()
很好。注意,这也允许我们删除两个导入语句,因为我们不需要导入 pathlib 或 tempfile。
下面是两个相关的内置固定程序。
*tmpdir-类似于tmp_path,但返回一个py.path.local对象。py.path.local比pathlib更早,pathlib是在Python 3.4中加入的。py.path.local在pytest中被慢慢淘汰,而采用pathlib版本。因此,我推荐使用 tmp_path。
tmpdir_factory-类似于tmp_path_factory,只是它的mktemp函数返回py.path.local对象而不是pathlib.Path对象。
所有pytest临时目录固定的基础目录是由系统和用户决定的,包括一个pytest-NUM部分,其中NUM在每个会话中递增。基准目录在会话结束后立即保持原样,以便在测试失败时进行检查。pytest最终会对其进行清理。只有最近的几个临时基础目录被留在系统中。
如果需要,你也可以用pytest --basetemp=mydir指定你自己的基础目录。
使用capsys
有时应用程序代码向stdout、stderr等输出一些东西。
$ cards version
1.0.0
$ python -i
>>> import cards
>>> cards.__version__
'1.0.0'
测试的一个方法是用subprocess.run()实际运行命令,抓取输出,并与API中的版本进行比较。
import subprocess
def test_version_v1():
process = subprocess.run(
["cards", "version"], capture_output=True, text=True
)
output = process.stdout.rstrip()
assert output == cards.__version__
def test_version_v2(capsys):
cards.cli.version()
output = capsys.readouterr().out.rstrip()
assert output == cards.__version__
capsys能够捕获写到stdout和stderr的数据。我们可以直接调用CLI中实现这一功能的方法,并使用capsys来读取输出。
capsys的另一个特点是能够暂时禁用pytest的正常输出捕获。pytest通常捕获你的测试和应用程序代码的输出。这包括打印语句。
ch4/test_print.py
def test_normal():
print("\nnormal print")
def test_fail():
print("\nprint in failing test")
assert False
# 另一种总是包括输出的方法是使用 capsys.disabled()
def test_disabled(capsys):
with capsys.disabled():
print("\ncapsys disabled print")
如果我们运行它,没有看到任何输出。
# pytest捕获了所有的输出。这有助于保持命令行会话的清洁。
$ pytest test_print.py::test_normal
============================= test session starts =============================
platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
rootdir: D:\code\pytest_quick, configfile: pytest.ini
plugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0
collected 1 item
test_print.py . [100%]
============================== 1 passed in 0.10s ==============================
# 有时我们希望看到所有的输出,即使是在通过测试时。我们可以使用-s或-capture=no标志来实现。
$ pytest -s test_print.py::test_normal
============================= test session starts =============================
platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
rootdir: D:\code\pytest_quick, configfile: pytest.ini
plugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0
collected 1 item
test_print.py
normal print
.
============================== 1 passed in 0.07s ==============================
$ pytest test_print.py::test_fail
============================= test session starts =============================
platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
rootdir: D:\code\pytest_quick, configfile: pytest.ini
plugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0
collected 1 item
test_print.py F [100%]
================================== FAILURES ===================================
__________________________________ test_fail __________________________________
def test_fail():
print("\nprint in failing test")
> assert False
E assert False
test_print.py:7: AssertionError
---------------------------- Captured stdout call -----------------------------
print in failing test
=========================== short test summary info ===========================
FAILED test_print.py::test_fail - assert False
============================== 1 failed in 0.13s ==============================
$ pytest test_print.py::test_disabled
============================= test session starts =============================
platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
rootdir: D:\code\pytest_quick, configfile: pytest.ini
plugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0
collected 1 item
test_print.py
capsys disabled print
. [100%]
============================== 1 passed in 0.08s ==============================
以下是相关的内置Fixture。
- capfd-类似于capsys,但捕获文件描述符1和2,通常与stdout和stderr相同。
- capsysbinary- capsys捕捉文本,capsysbinary捕捉字节。
- capfdbinary-捕获文件描述符1和2上的字节。
- caplog-捕获用日志包编写的输出。