pytest-describe
pytest-describe is a plugin for the pytest testing framework that enables writing tests in an RSpec/Jasmine-style format, using arbitrary nested `describe-blocks`. This approach helps organize tests by context and behavior, making test suites more readable and maintainable. The current version is 3.1.0, and it is actively maintained with regular updates to support newer Python and pytest versions.
Warnings
- breaking pytest-describe versions are tightly coupled to specific ranges of pytest and Python versions. For instance, version 3.1.0 supports pytest 6.0 to 9.0 and Python 3.9 to 3.14. Upgrading your pytest or Python environment without verifying compatibility against pytest-describe's release notes can lead to unexpected test collection failures or runtime errors.
- gotcha Within `describe_` blocks, only functions starting with `describe_` or any non-underscore prefix are collected as tests. Functions that start with a single underscore (e.g., `def _helper_function():`) are explicitly *not* collected as tests. This is intended for helper functions but can be a gotcha if you accidentally prefix a test with an underscore, causing it to be skipped.
- gotcha By default, `pytest-describe` only recognizes functions starting with `describe_` as test blocks. If you prefer to use alternative prefixes (e.g., `context_`, `feature_`) for your organizational blocks, you must explicitly configure these in your pytest configuration file (e.g., `pyproject.toml` or `pytest.ini`) using the `describe_prefixes` option.
Install
-
pip install pytest-describe
Imports
- behaves_like
from pytest_describe import behaves_like
- describe_ / it_ (naming conventions)
def describe_feature(): def it_should_do_something(): pass
Quickstart
import pytest
class Wallet:
def __init__(self, initial_amount=0):
self.balance = initial_amount
def spend_cash(self, amount):
if self.balance < amount:
raise ValueError(f'Not enough available to spend {amount}')
self.balance -= amount
def add_cash(self, amount):
self.balance += amount
def describe_wallet():
def describe_start_empty():
@pytest.fixture
def wallet():
return Wallet()
def initial_amount_is_zero(wallet):
assert wallet.balance == 0
def can_add_cash(wallet):
wallet.add_cash(80)
assert wallet.balance == 80
def cannot_spend_if_empty(wallet):
with pytest.raises(ValueError):
wallet.spend_cash(10)
def describe_with_starting_balance():
@pytest.fixture
def wallet():
return Wallet(20)
def initial_amount_is_twenty(wallet):
assert wallet.balance == 20
def describe_adding():
def add_little_cash(wallet):
wallet.add_cash(5)
assert wallet.balance == 25
def add_much_cash(wallet):
wallet.add_cash(980)
assert wallet.balance == 1000
def describe_spending():
def spend_cash(wallet):
wallet.spend_cash(15)
assert wallet.balance == 5
def spend_too_much_cash(wallet):
with pytest.raises(ValueError):
wallet.spend_cash(25)