| 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.pytest_<功能>_<条件>_<预期>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 -vpytest --pdb 进入调试器pytest --full-tracepytest --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 测试的首选工具。持续实践并探索其生态系统,将显著提升您的测试效率和代码质量。
阅读原文:原文链接