DEV Community

郑沛沛
郑沛沛

Posted on

Pytest Like a Pro: Fixtures, Mocks, and Patterns That Actually Work

Writing tests shouldn't feel like a chore. With the right pytest patterns, tests become fast to write and easy to maintain.

Why pytest Over unittest

# unittest — verbose
import unittest

class TestMath(unittest.TestCase):
    def test_add(self):
        self.assertEqual(1 + 1, 2)

# pytest — clean
def test_add():
    assert 1 + 1 == 2
Enter fullscreen mode Exit fullscreen mode

Less boilerplate, better error messages, powerful fixtures.

Fixtures: Setup Done Right

import pytest

@pytest.fixture
def sample_user():
    return {"name": "Alice", "email": "alice@example.com", "role": "admin"}

@pytest.fixture
def db_connection():
    conn = create_connection("test.db")
    yield conn  # test runs here
    conn.close()  # teardown after test

def test_user_is_admin(sample_user):
    assert sample_user["role"] == "admin"

def test_insert_user(db_connection, sample_user):
    db_connection.insert("users", sample_user)
    result = db_connection.find("users", {"name": "Alice"})
    assert result is not None
Enter fullscreen mode Exit fullscreen mode

Parametrize: One Test, Many Cases

@pytest.mark.parametrize("input_val,expected", [
    ("hello", 5),
    ("", 0),
    ("world!", 6),
    ("  spaces  ", 10),
])
def test_string_length(input_val, expected):
    assert len(input_val) == expected

@pytest.mark.parametrize("a,b,result", [
    (1, 2, 3),
    (-1, 1, 0),
    (0, 0, 0),
    (100, -50, 50),
])
def test_addition(a, b, result):
    assert a + b == result
Enter fullscreen mode Exit fullscreen mode

Mocking External Services

from unittest.mock import patch, MagicMock

def get_weather(city):
    import requests
    response = requests.get(f"https://api.weather.com/{city}")
    return response.json()["temperature"]

def test_get_weather():
    mock_response = MagicMock()
    mock_response.json.return_value = {"temperature": 72}

    with patch("requests.get", return_value=mock_response) as mock_get:
        temp = get_weather("NYC")
        assert temp == 72
        mock_get.assert_called_once_with("https://api.weather.com/NYC")
Enter fullscreen mode Exit fullscreen mode

Testing Exceptions

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

def test_divide_by_zero():
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(10, 0)
Enter fullscreen mode Exit fullscreen mode

Temporary Files and Directories

def test_file_processing(tmp_path):
    # tmp_path is a built-in fixture
    test_file = tmp_path / "data.txt"
    test_file.write_text("line1\nline2\nline3")

    result = count_lines(str(test_file))
    assert result == 3
Enter fullscreen mode Exit fullscreen mode

conftest.py: Shared Fixtures

# conftest.py
import pytest

@pytest.fixture(scope="session")
def api_client():
    client = TestClient(app)
    yield client

@pytest.fixture(autouse=True)
def reset_db(db_connection):
    yield
    db_connection.rollback()
Enter fullscreen mode Exit fullscreen mode

Useful CLI Options

pytest -v                    # verbose output
pytest -x                    # stop on first failure
pytest -k "test_user"        # run tests matching pattern
pytest --tb=short            # shorter tracebacks
pytest -n auto               # parallel execution (pytest-xdist)
pytest --cov=myapp           # coverage report
Enter fullscreen mode Exit fullscreen mode

Testing Async Code

import pytest

@pytest.mark.asyncio
async def test_async_fetch():
    result = await fetch_data("https://api.example.com")
    assert result["status"] == "ok"
Enter fullscreen mode Exit fullscreen mode

Key Patterns

  1. One assertion per test when possible
  2. Use fixtures for setup, not helper functions in tests
  3. Parametrize instead of copy-pasting similar tests
  4. Mock at the boundary (API calls, database, file system)
  5. Use conftest.py for shared fixtures
  6. Run with --cov to track coverage

Good tests are fast, isolated, and readable. pytest makes all three easy.

🚀 Level up your AI workflow! Check out my AI Developer Mega Prompt Pack — 80 battle-tested prompts for developers. $9.99

Top comments (0)