返回 Skill 列表
extension
分类: 开发与工程无需 API Key

pytest-skill

生成生产级的pytest测试,包括fixture、参数化、标记、模拟和conftest模式。当用户提到'pytest', 'conftest', '@pytest.fixture', '@pytest.mark', 'Python test'时使用。触发词包括:'pytest', 'conftest', 'Python test', 'parametrize', 'Python unit test'。

person作者: jakexiaohubgithub

Pytest Testing Skill

Core Patterns

Basic Test

import pytest

def test_addition():
    assert 2 + 3 == 5

def test_exception():
    with pytest.raises(ValueError, match="invalid"):
        int("not_a_number")

class TestCalculator:
    def test_add(self):
        calc = Calculator()
        assert calc.add(2, 3) == 5

    def test_divide_by_zero(self):
        with pytest.raises(ZeroDivisionError):
            Calculator().divide(10, 0)

Fixtures

@pytest.fixture
def calculator():
    return Calculator()

@pytest.fixture
def db_connection():
    conn = Database.connect("test_db")
    yield conn  # teardown after yield
    conn.rollback()
    conn.close()

@pytest.fixture(scope="module")
def api_client():
    client = APIClient(base_url="http://localhost:8000")
    yield client
    client.logout()

# conftest.py - shared fixtures
@pytest.fixture(autouse=True)
def reset_state():
    State.reset()
    yield
    State.cleanup()

# Usage
def test_add(calculator):
    assert calculator.add(2, 3) == 5

Parametrize

@pytest.mark.parametrize("input,expected", [
    ("hello", 5), ("", 0), ("pytest", 6),
])
def test_string_length(input, expected):
    assert len(input) == expected

@pytest.mark.parametrize("a,b,expected", [
    (2, 3, 5), (-1, 1, 0), (0, 0, 0),
])
def test_add(calculator, a, b, expected):
    assert calculator.add(a, b) == expected

Markers

@pytest.mark.slow
def test_large_dataset(): ...

@pytest.mark.skip(reason="Not implemented")
def test_future_feature(): ...

@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_permissions(): ...

@pytest.mark.xfail(reason="Known bug #123")
def test_known_bug(): ...

Mocking

from unittest.mock import patch, MagicMock

def test_send_email(mocker):
    mock_smtp = mocker.patch("myapp.email.smtplib.SMTP")
    send_welcome_email("user@test.com")
    mock_smtp.return_value.sendmail.assert_called_once()

def test_api_call(mocker):
    mock_response = mocker.Mock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"users": [{"name": "Alice"}]}
    mocker.patch("myapp.service.requests.get", return_value=mock_response)
    users = get_users()
    assert len(users) == 1

@patch("myapp.service.database")
def test_save_user(mock_db):
    mock_db.save.return_value = True
    assert save_user({"name": "Alice"}) is True
    mock_db.save.assert_called_once()

Assertions

assert x == y
assert x != y
assert x in collection
assert isinstance(obj, MyClass)
assert 0.1 + 0.2 == pytest.approx(0.3)

with pytest.raises(ValueError) as exc_info:
    raise ValueError("bad")
assert "bad" in str(exc_info.value)

Anti-Patterns

| Bad | Good | Why | |-----|------|-----| | self.assertEqual() | assert x == y | pytest rewrites give better output | | Setup in __init__ | @pytest.fixture | Lifecycle management | | Global state | Fixture with yield | Proper cleanup | | Huge test functions | Small focused tests | Easier debugging |

Quick Reference

| Task | Command | |------|---------| | Run all | pytest | | Run file | pytest tests/test_login.py | | Run specific | pytest tests/test_login.py::test_login_success | | By marker | pytest -m slow | | By keyword | pytest -k "login and not invalid" | | Verbose | pytest -v | | Stop first fail | pytest -x | | Last failed | pytest --lf | | Coverage | pytest --cov=myapp --cov-report=html | | Parallel | pytest -n auto (pytest-xdist) |

pyproject.toml

[tool.pytest.ini_options]
testpaths = ["tests"]
markers = ["slow: slow tests", "integration: integration tests"]
addopts = "-v --tb=short"

Deep Patterns

For production-grade patterns, see reference/playbook.md:

| Section | What's Inside | |---------|--------------| | §1 Config | pytest.ini + pyproject.toml with markers, coverage | | §2 Fixtures | Scoping, factories, teardown, autouse, tmp_path | | §3 Parametrize | Basic, with IDs, cartesian, indirect | | §4 Mocking | pytest-mock, monkeypatch, spies, env vars | | §5 Async | pytest-asyncio, async fixtures, async client | | §6 Exceptions | pytest.raises(match=), warnings | | §7 Markers & Plugins | Custom markers, collection hooks | | §8 Class-Based | Nested classes, autouse setup | | §9 CI/CD | GitHub Actions matrix, coverage gates | | §10 Debugging Table | 10 common problems with fixes | | §11 Best Practices | 15-item production checklist |