pytest

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Basic Test Structure

基本测试结构

python
import pytest

class TestUserService:
    def test_create_user_success(self):
        user = create_user(name="John", email="john@test.com")
        assert user.name == "John"
        assert user.email == "john@test.com"

    def test_create_user_invalid_email_fails(self):
        with pytest.raises(ValueError, match="Invalid email"):
            create_user(name="John", email="invalid")
python
import pytest

class TestUserService:
    def test_create_user_success(self):
        user = create_user(name="John", email="john@test.com")
        assert user.name == "John"
        assert user.email == "john@test.com"

    def test_create_user_invalid_email_fails(self):
        with pytest.raises(ValueError, match="Invalid email"):
            create_user(name="John", email="invalid")

Fixtures

Fixtures

python
import pytest

@pytest.fixture
def user():
    """Create a test user."""
    return User(name="Test User", email="test@example.com")

@pytest.fixture
def authenticated_client(client, user):
    """Client with authenticated user."""
    client.force_login(user)
    return client
python
import pytest

@pytest.fixture
def user():
    """创建测试用户。"""
    return User(name="Test User", email="test@example.com")

@pytest.fixture
def authenticated_client(client, user):
    """已认证用户的客户端。"""
    client.force_login(user)
    return client

Fixture with teardown

带清理操作的Fixture

@pytest.fixture def temp_file(): path = Path("/tmp/test_file.txt") path.write_text("test content") yield path # Test runs here path.unlink() # Cleanup after test
@pytest.fixture def temp_file(): path = Path("/tmp/test_file.txt") path.write_text("test content") yield path # 测试在此处运行 path.unlink() # 测试后清理

Fixture scopes

Fixture作用域

@pytest.fixture(scope="module") # Once per module @pytest.fixture(scope="class") # Once per class @pytest.fixture(scope="session") # Once per test session
undefined
@pytest.fixture(scope="module") # 每个模块执行一次 @pytest.fixture(scope="class") # 每个类执行一次 @pytest.fixture(scope="session") # 每个测试会话执行一次
undefined

conftest.py

conftest.py

python
undefined
python
undefined

tests/conftest.py - Shared fixtures

tests/conftest.py - 共享Fixtures

import pytest
@pytest.fixture def db_session(): session = create_session() yield session session.rollback()
@pytest.fixture def api_client(): return TestClient(app)
undefined
import pytest
@pytest.fixture def db_session(): session = create_session() yield session session.rollback()
@pytest.fixture def api_client(): return TestClient(app)
undefined

Mocking

Mocking

python
from unittest.mock import patch, MagicMock

class TestPaymentService:
    def test_process_payment_success(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.return_value = {"id": "ch_123", "status": "succeeded"}

            result = process_payment(amount=100)

            assert result["status"] == "succeeded"
            mock_stripe.charge.assert_called_once_with(amount=100)

    def test_process_payment_failure(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.side_effect = PaymentError("Card declined")

            with pytest.raises(PaymentError):
                process_payment(amount=100)
python
from unittest.mock import patch, MagicMock

class TestPaymentService:
    def test_process_payment_success(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.return_value = {"id": "ch_123", "status": "succeeded"}

            result = process_payment(amount=100)

            assert result["status"] == "succeeded"
            mock_stripe.charge.assert_called_once_with(amount=100)

    def test_process_payment_failure(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.side_effect = PaymentError("Card declined")

            with pytest.raises(PaymentError):
                process_payment(amount=100)

MagicMock for complex objects

用于复杂对象的MagicMock

def test_with_mock_object(): mock_user = MagicMock() mock_user.id = "user-123" mock_user.name = "Test User" mock_user.is_active = True
result = get_user_info(mock_user)
assert result["name"] == "Test User"
undefined
def test_with_mock_object(): mock_user = MagicMock() mock_user.id = "user-123" mock_user.name = "Test User" mock_user.is_active = True
result = get_user_info(mock_user)
assert result["name"] == "Test User"
undefined

Parametrize

Parametrize

python
@pytest.mark.parametrize("input,expected", [
    ("hello", "HELLO"),
    ("world", "WORLD"),
    ("pytest", "PYTEST"),
])
def test_uppercase(input, expected):
    assert input.upper() == expected

@pytest.mark.parametrize("email,is_valid", [
    ("user@example.com", True),
    ("invalid-email", False),
    ("", False),
    ("user@.com", False),
])
def test_email_validation(email, is_valid):
    assert validate_email(email) == is_valid
python
@pytest.mark.parametrize("input,expected", [
    ("hello", "HELLO"),
    ("world", "WORLD"),
    ("pytest", "PYTEST"),
])
def test_uppercase(input, expected):
    assert input.upper() == expected

@pytest.mark.parametrize("email,is_valid", [
    ("user@example.com", True),
    ("invalid-email", False),
    ("", False),
    ("user@.com", False),
])
def test_email_validation(email, is_valid):
    assert validate_email(email) == is_valid

Markers

Markers

python
undefined
python
undefined

pytest.ini or pyproject.toml

pytest.ini or pyproject.toml

[tool.pytest.ini_options] markers = [ "slow: marks tests as slow", "integration: marks integration tests", ]
[tool.pytest.ini_options] markers = [ "slow: 标记测试为慢测试", "integration: 标记为集成测试", ]

Usage

使用示例

@pytest.mark.slow def test_large_data_processing(): ...
@pytest.mark.integration def test_database_connection(): ...
@pytest.mark.skip(reason="Not implemented yet") def test_future_feature(): ...
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only") def test_unix_specific(): ...
@pytest.mark.slow def test_large_data_processing(): ...
@pytest.mark.integration def test_database_connection(): ...
@pytest.mark.skip(reason="尚未实现") def test_future_feature(): ...
@pytest.mark.skipif(sys.platform == "win32", reason="仅支持Unix系统") def test_unix_specific(): ...

Run specific markers

运行指定标记的测试

pytest -m "not slow"

pytest -m "not slow"

pytest -m "integration"

pytest -m "integration"

undefined
undefined

Async Tests

异步测试

python
import pytest

@pytest.mark.asyncio
async def test_async_function():
    result = await async_fetch_data()
    assert result is not None
python
import pytest

@pytest.mark.asyncio
async def test_async_function():
    result = await async_fetch_data()
    assert result is not None

Commands

命令

bash
pytest                          # Run all tests
pytest -v                       # Verbose output
pytest -x                       # Stop on first failure
pytest -k "test_user"           # Filter by name
pytest -m "not slow"            # Filter by marker
pytest --cov=src                # With coverage
pytest -n auto                  # Parallel (pytest-xdist)
pytest --tb=short               # Short traceback
bash
pytest                          # 运行所有测试
pytest -v                       # 详细输出
pytest -x                       # 遇到第一个失败即停止
pytest -k "test_user"           # 按名称过滤测试
pytest -m "not slow"            # 按标记过滤测试
pytest --cov=src                # 生成测试覆盖率报告
pytest -n auto                  # 并行运行测试(需pytest-xdist)
pytest --tb=short               # 简化回溯信息

Keywords

关键词

pytest, python, testing, fixtures, mocking, parametrize, markers
pytest, Python, 测试, Fixtures, Mocking, Parametrize, 标记