Skip to main content

Alternatives to Given-When-Then for Python Test Docstrings

· 5 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

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 of pytest 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.