█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Software Engineering/Testing/Unit Testing in Python
45 minIntermediate

Unit Testing in Python

After this lesson, you will be able to: Test Python code with pytest, share setup with fixtures, cover many cases with parametrize, and mock dependencies with unittest.mock.

Python is the other language LastWrite students ship, so testing it well matters. pytest is the de facto standard. This lesson covers the runner, fixtures, parametrization, and mocking, mapping each idea back to what you just learned in JavaScript.

Prerequisites:Unit Testing in JavaScript and TypeScript

pytest basics and fixtures

pytest discovers test_*.py files and test_* functions; assertions use plain assert. Fixtures provide reusable setup.

python
# discount.py
def apply_discount(price, code):
if code == 'HALF':
return price / 2
if code == 'TENOFF':
return max(0, price - 10)
return price
# test_discount.py
import pytest
from discount import apply_discount
def test_halves_for_half():
assert apply_discount(40, 'HALF') == 20
def test_never_below_zero():
assert apply_discount(5, 'TENOFF') == 0
# A fixture: reusable setup injected by name
@pytest.fixture
def sample_cart():
return [{'id': 'a', 'price': 10}, {'id': 'b', 'price': 5}]
def test_cart_total(sample_cart):
assert sum(item['price'] for item in sample_cart) == 15
# Install: pip install pytest pytest-cov
# Run: pytest Coverage: pytest --cov

Parametrize: one test, many cases

parametrize runs the same test body across a table of inputs and expected outputs. It replaces copy-pasted near-identical tests.

python
import pytest
from discount import apply_discount
@pytest.mark.parametrize('price, code, expected', [
(40, 'HALF', 20),
(5, 'TENOFF', 0),
(40, 'NOPE', 40),
(100, 'TENOFF', 90),
])
def test_apply_discount(price, code, expected):
assert apply_discount(price, code) == expected
# Each row is reported as its own test, so a failure tells you exactly
# which input broke.

Mocking with unittest.mock

Patch a dependency at its boundary so the test stays offline and deterministic. This is the Python equivalent of vi.mock.

python
from unittest.mock import patch, MagicMock
from weather import get_weather_summary
# Patch where the name is USED, not where it's defined.
@patch('weather.requests.get')
def test_summary(mock_get):
mock_get.return_value = MagicMock(
status_code=200,
json=lambda: {'tempC': 21, 'condition': 'Clear'},
)
assert get_weather_summary('London') == 'London: 21C, Clear'
mock_get.assert_called_once()
Quick Check

You have eight near-identical pytest functions that differ only in input and expected output. What's the idiomatic fix?

Pick the best answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Unit Testing in JavaScript and TypeScript
Back to Testing
Integration Testing→