pytest is a popular Python testing framework that makes it simple, readable, and powerful to write and run automated tests. It supports simple unit tests, complex functional tests, fixtures, parametrization, and rich plugins & reporting.
test_*.py or *_test.py.assert keyword; pytest gives detailed failure messages.slow, smoke, db, etc., and selectively run them.test_something.py or something_test.py.test_.pytest from the terminal.Most pytest tests follow the AAA pattern:
assert statements.Fixtures are functions marked with @pytest.fixture that return reusable objects. Tests request fixtures just by listing them as function parameters. pytest handles creation, reuse, and cleanup.
# math_utils.py
def add(a, b):
return a + b
def divide(a, b):
return a / b
# test_math_utils.py
import math_utils
def test_add():
# Arrange & Act
result = math_utils.add(2, 3)
# Assert
assert result == 5
def test_divide():
result = math_utils.divide(10, 2)
assert result == 5
# conftest.py (shared fixtures)
import pytest
@pytest.fixture
def sample_numbers():
print("Setting up sample_numbers fixture")
nums = [1, 2, 3, 4, 5]
yield nums
print("Tearing down sample_numbers fixture")
# test_with_fixture.py
def test_sum(sample_numbers):
total = sum(sample_numbers)
assert total == 15
def test_length(sample_numbers):
assert len(sample_numbers) == 5
# Example of parametrized tests with pytest
import pytest
def is_even(n: int) -> bool:
return n % 2 == 0
# Each pair is (input_value, expected_result)
@pytest.mark.parametrize(
"value, expected",
[
(2, True),
(3, False),
(10, True),
(15, False),
],
)
def test_is_even(value, expected):
# Assert that is_even returns the expected result
assert is_even(value) == expected
import pytest
# Basic division function
def divide(a, b):
return a / b
# Verify that dividing by zero raises ZeroDivisionError
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
import pytest
@pytest.mark.slow
def test_heavy_computation():
total = 0
for i in range(10_000_000):
total += i
assert total > 0
@pytest.mark.api
def test_api_call():
# imagine calling an external API here
response_status = 200
assert response_status == 200
# Run only slow tests:
# pytest -m slow
#
# Run tests marked "api" but not "slow":
# pytest -m "api and not slow"
Once your test files are ready, open a terminal in your project directory and run pytest. pytest will automatically discover and execute tests.
$ pytest
============================= test session starts =============================
collected 4 items
test_math_utils.py .. [ 50%]
test_with_fixture.py .. [100%]
============================== 4 passed in 0.03s ==============================
Each dot (.) represents a passing test. If a test fails, pytest shows a F plus a detailed traceback and a helpful comparison of expected vs actual values.
test_user_login_with_valid_credentials.calculator.py with functions: add, subtract, multiply, divide. Then write a corresponding test_calculator.py using pytest.add function that checks at least five different input combinations.divide raises ZeroDivisionError when the denominator is zero (use pytest.raises).@pytest.mark.integration on one test and practice running only those tests with pytest -m integration.