Alternatives to Given-When-Then for Python Test Docstrings
For docstrings in Python tests, there isn't a single technique that's universally "better" than Given-When-Then. The best technique depends on your project's needs, your team's familiarity with different styles, and the specific type of testing you're doing.
The Trade-Offs of Given-When-Then
Given-When-Then is a behavioral style. Its strength lies in its ability to describe a test in plain language, making it accessible to non-technical stakeholders and focusing on the "why" behind the code [1]. It's excellent for integration and end-to-end tests where the behavior of a system is more important than the minute details of a single function.
However, for some developers, Given-When-Then can feel verbose or even cumbersome for simple unit tests. When you're testing a small, isolated function, the strict three-part structure can feel like overkill.
Alternatives to Given-When-Then
Here are some alternative techniques, each with its own advantages:
1. The Simple, Direct Docstring
For straightforward unit tests, a simple, declarative docstring can be more concise and just as effective. This style gets straight to the point, explaining what is being tested and what the expected outcome is.
Example:
def test_add_two_numbers():
"""Test that the add function correctly sums two positive integers."""
# ... test code ...
This is a minimalist approach that is easy to write and read, especially for a developer already familiar with the codebase.
2. The "Expectation-First" Approach
This style puts the expected outcome at the beginning of the docstring. It's an effective way to communicate the goal of the test immediately.
Example:
def test_returns_correct_total_for_shopping_cart():
"""The shopping cart total should be the sum of all item prices."""
# ... test code ...
This method is particularly useful for quickly scanning test files to understand what functionality is being asserted.
3. The Test-as-Documentation (Pytest
and doctest
)
Some developers forgo extensive docstrings in favor of making the test function name and code self-documenting.
- Pytest Naming Conventions: By using descriptive function names, such as
test_user_is_created_with_valid_email
, the test's purpose is immediately clear. This is a powerful, built-in feature ofpytest
that reduces the need for verbose docstrings [2]. doctest
: This built-in Python module allows you to write tests directly within the docstrings of your functions. It's a highly integrated approach where the test is an example of the function's usage, serving a dual purpose as documentation and a test [3].
Example of doctest
:
def add(a, b):
"""
Returns the sum of two numbers.
>>> add(2, 2)
4
>>> add(3, 5)
8
"""
return a + b
Conclusion: A Blended Approach is Often Best
Instead of choosing one style exclusively, a blended approach is often the most practical.
- Use Given-When-Then for complex integration tests and behavioral tests where you need to describe a system's interaction in plain language.
- Use simple, descriptive docstrings or function names for straightforward unit tests on isolated functions.
- Consider
doctest
for functions where an example in the docstring serves both as a test and as clear documentation of the function's behavior.