30天学会Python编程:30.Pytest 实践教程
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
|
function | ||
class | ||
module | ||
package | ||
session |
@pytest.fixture(scope="module")
def shared_resource():
print("\n初始化共享资源")
resource = create_expensive_resource()
yield resource
print("\n清理共享资源")
resource.cleanup()
import pytest
@pytest.fixture(params=["utf-8", "utf-16", "ascii"])
def encoding(request):
return request.param
def test_encoding(encoding):
text = "Hello World"
encoded = text.encode(encoding)
decoded = encoded.decode(encoding)
assert decoded == text
Pytest 提供许多有用的内置 fixtures:
def test_temp_dir(tmp_path):
"""使用临时目录 fixture"""
file = tmp_path / "test.txt"
file.write_text("Hello pytest")
assert file.read_text() == "Hello pytest"
def test_capsys(capsys):
"""捕获标准输出"""
print("Hello pytest")
captured = capsys.readouterr()
assert captured.out == "Hello pytest\n"
import pytest
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(5, -5, 0),
(100, 200, 300),
])
def test_add(a, b, expected):
assert add(a, b) == expected
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_combinations(x, y):
assert x + y == y + x
@pytest.mark.parametrize("input,expected", [
("3+5", 8),
("2+4", 6),
("6*9", 42, marks=pytest.mark.xfail),
], ids=["3+5=8", "2+4=6", "6*9=42 (xfail)"])
def test_eval(input, expected):
assert eval(input) == expected
@pytest.mark.skip(reason="功能尚未实现")
def test_unimplemented():
assert False
@pytest.mark.skipif(sys.version_info < (3, 8),
reason="需要 Python 3.8+")
def test_python38_feature():
assert True
@pytest.mark.xfail
def test_experimental():
assert False # 预期失败
# conftest.py
def pytest_configure(config):
config.addinivalue_line(
"markers", "slow: 标记为慢速测试"
)
@pytest.mark.slow
def test_large_data_processing():
time.sleep(10)
assert True
运行指定标记的测试:
pytest -m slow # 只运行慢测试
pytest -m "not slow" # 排除慢测试
pip install pytest-cov | ||
pip install pytest-xdist | ||
pip install pytest-mock | ||
pip install pytest-html | ||
pip install pytest-asyncio |
# 生成覆盖率报告
pytest --cov=my_project --cov-report=html
# 并行运行测试
pytest -n auto
# 生成 HTML 报告
pytest --html=report.html
project/
├── src/
│ ├── __init__.py
│ ├── module1.py
│ └── module2.py
└── tests/
├── unit/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_module1.py
│ └── test_module2.py
├── integration/
│ └── test_integration.py
└── functional/
└── test_functional.py
test_<模块名>.py
或 <模块名>_test.py
test_<功能>_<条件>_<预期>
Test<功能>
import pytest
def test_mocking(mocker):
# 使用 pytest-mock 插件
mock_requests = mocker.patch("requests.get")
mock_requests.return_value.status_code = 200
response = requests.get("http://example.com")
assert response.status_code == 200
mock_requests.assert_called_once_with("http://example.com")
def test_monkeypatch(monkeypatch):
# 临时修改环境变量
monkeypatch.setenv("DEBUG", "True")
assert os.getenv("DEBUG") == "True"
# 修改系统函数
monkeypatch.setattr(time, "sleep", lambda x: None)
time.sleep(10) # 实际上不会等待
import pytest
import asyncio
@pytest.mark.asyncio
async def test_async_code():
result = await async_function()
assert result == "expected"
# conftest.py
def pytest_runtest_logreport(report):
if report.when == "call" and report.failed:
print(f"\n测试失败: {report.nodeid}")
print(f"错误信息: {report.longreprtext}")
from fastapi.testclient import TestClient
from myapp.main import app
@pytest.fixture
def client():
return TestClient(app)
def test_homepage(client):
response = client.get("/")
assert response.status_code == 200
assert "Welcome" in response.text
def test_login(client):
response = client.post("/login", json={
"username": "admin",
"password": "secret"
})
assert response.status_code == 200
assert "token" in response.json()
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
@pytest.fixture(scope="module")
def db_session():
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
yield session
session.close()
def test_create_user(db_session):
user = User(name="Alice", email="alice@example.com")
db_session.add(user)
db_session.commit()
saved = db_session.query(User).filter_by(email="alice@example.com").first()
assert saved is not None
assert saved.name == "Alice"
pytest -v
pytest --pdb
进入调试器pytest --full-trace
pytest --lf
# 找出最慢的测试
pytest --durations=10
# 并行运行测试
pytest -n auto
# 禁用插件
pytest -p no:cov -p no:xdist
# pytest.ini 配置文件
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
addopts = -v --color=yes
markers =
slow: 标记为慢速测试
integration: 集成测试
通过本教程,我们可以掌握 Pytest 从基础到高级的各种技巧。Pytest 的强大功能和灵活性使其成为 Python 测试的首选工具。持续实践并探索其生态系统,将显著提升您的测试效率和代码质量。
阅读原文:原文链接