Overview
Use the pytest framework to write high-quality, maintainable Python test cases. Supports pytest core features such as simple assertions, automatic discovery, fixtures, and parameterized tests.
Quick Start
Basic test structure
# test_sample.py
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 4
Run tests:
pytest
Test file naming conventions
- Test files:
test_*.pyor*_test.py - Test functions:
test_* - Test classes:
Test*
Core Capabilities
1. Write basic tests
Use simple assert statements; pytest provides detailed failure information:
def test_addition():
assert 1 + 1 == 2
def test_string_operations():
text = "hello"
assert text.upper() == "HELLO"
assert len(text) == 5
2. Use Fixtures
Fixtures are used to manage test resources and dependencies:
import pytest
@pytest.fixture
def sample_data():
return {"name": "test", "value": 42}
def test_with_fixture(sample_data):
assert sample_data["value"] == 42
Advanced fixtures usage: see references/fixtures.md
3. Parameterized tests
Use @pytest.mark.parametrize to reduce duplicate code:
@pytest.mark.parametrize("input,expected", [
(3, 4),
(5, 6),
(10, 11),
])
def test_increment(input, expected):
assert input + 1 == expected
More parameterization patterns: see references/parametrize.md
4. Assertion techniques
Take advantage of pytest's assertion introspection feature:
def test_dict_comparison():
expected = {"a": 1, "b": 2}
actual = {"a": 1, "b": 3}
assert actual == expected # pytest会显示详细的差异
Assertion best practices: see references/assertions.md
5. Test organization
Organize by functionality
tests/
├── test_auth.py
├── test_database.py
├── test_api.py
└── conftest.py # 共享fixtures
Use conftest.py
Define shared fixtures in conftest.py:
# conftest.py
@pytest.fixture
def db_connection():
conn = create_connection()
yield conn
conn.close()
6. Exception testing
Use pytest.raises to test exceptions:
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
def test_value_error():
with pytest.raises(ValueError) as exc_info:
int("invalid")
assert "invalid literal" in str(exc_info.value)
7. Skipping and expected failures
@pytest.mark.skip(reason="功能未实现")
def test_not_implemented():
pass
@pytest.mark.skipif(sys.version_info < (3, 8), reason="需要Python 3.8+")
def test_python38_feature():
pass
@pytest.mark.xfail
def test_known_failure():
assert False # 预期失败
Testing Best Practices
Test naming
- Use descriptive test names:
test_user_login_with_valid_credentials - Follow the AAA pattern: Arrange → Act → Assert
def test_calculate_total_with_discount():
# Arrange
cart = Cart(items=[Item(price=100), Item(price=50)])
discount = 0.1
# Act
total = cart.calculate_total(discount)
# Assert
assert total == 135
Test isolation
- Each test should run independently
- Use fixtures to ensure isolation between tests
- Avoid dependencies between tests
More best practices: see references/best-practices.md
Running Tests
Basic commands
# 运行所有测试
pytest
# 运行特定文件
pytest tests/test_auth.py
# 运行特定测试函数
pytest tests/test_auth.py::test_login
# 运行匹配模式的测试
pytest -k "login"
# 显示详细输出
pytest -v
# 显示print语句输出
pytest -s
# 在第一个失败时停止
pytest -x
# 运行上次失败的测试
pytest --lf
Test coverage
# 生成覆盖率报告
pytest --cov=src
# 生成HTML报告
pytest --cov=src --cov-report=html
Debugging Failed Tests
View detailed error information
pytest -v --tb=long
Debug with pdb
def test_debugging():
import pdb; pdb.set_trace()
result = complex_calculation()
assert result == expected
Or on the command line:
pytest --pdb
Resources
references/
Detailed reference documentation:
- fixtures.md - complete fixtures usage, scopes, parameterized fixtures
- parametrize.md - various patterns and techniques for parameterized tests
- assertions.md - assertion techniques, custom assertion messages
- best-practices.md - best practices such as test organization, naming conventions, and test isolation
assets/
- test_template.py - standard test file templates, including common patterns and structures