Python Unit Testing — pytest & Test-Driven Development

Python QualityTestingFree Lesson

Advertisement

Python Unit Testing — pytest & Test-Driven Development

Testing ensures your code works correctly and continues to work as you make changes.

Learning Objectives

  • Write tests with pytest
  • Use fixtures for test setup
  • Parametrize tests for multiple inputs
  • Mock external dependencies

pytest Basics

def add(a, b):
    return a + b

def test_add_positive():
    assert add(2, 3) == 5

def test_add_negative():
    assert add(-1, -1) == -2

def test_add_zero():
    assert add(0, 5) == 5

# Run: pytest test_calculator.py

Fixtures

import pytest

@pytest.fixture
def sample_data():
    return {"users": ["Alice", "Bob"], "count": 2}

@pytest.fixture
def db_connection():
    conn = create_connection()
    yield conn
    conn.close()

def test_user_count(sample_data):
    assert sample_data["count"] == len(sample_data["users"])

def test_database(db_connection):
    db_connection.execute("SELECT 1")

Parametrize

@pytest.mark.parametrize("input,expected", [
    (1, 2),
    (2, 4),
    (3, 6),
    (0, 0),
    (-1, -2),
])
def test_double(input, expected):
    assert double(input) == expected

Mocking

from unittest.mock import patch, MagicMock

def get_user_data(user_id):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json()

@patch('requests.get')
def test_get_user(mock_get):
    mock_get.return_value.json.return_value = {"name": "Alice"}
    result = get_user_data(1)
    assert result["name"] == "Alice"
    mock_get.assert_called_once()

Test Organization

# conftest.py — shared fixtures
@pytest.fixture
def api_client():
    return TestClient(app)

# test_api.py
class TestUserAPI:
    def test_create_user(self, api_client):
        response = api_client.post("/users", json={"name": "Alice"})
        assert response.status_code == 201

    def test_get_user(self, api_client):
        response = api_client.get("/users/1")
        assert response.status_code == 200

Key Takeaways

  1. Name test files test_*.py and functions test_*
  2. Use fixtures for reusable setup/teardown
  3. @pytest.mark.parametrize for data-driven tests
  4. Mock external dependencies (APIs, databases)
  5. Run tests with pytest -v for detailed output

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement