Python tutorials > Testing > Doctests > How to write doctests?
How to write doctests?
Doctests are a simple way to test your Python code directly within your docstrings. They allow you to embed test cases within the documentation itself, making the code more readable and easier to verify.
Basic Doctest Example
This example demonstrates a basic doctest. The add
function's docstring contains two test cases. Each test case consists of a Python expression preceded by >>>
, followed by the expected output on the next line. When doctest.testmod()
is run, it executes these test cases and compares the actual output with the expected output. If there's a mismatch, the test fails. The if __name__ == '__main__':
block ensures the doctests are only run when the script is executed directly.
def add(a, b):
"""Return the sum of a and b.
>>> add(2, 3)
5
>>> add(-1, 1)
0
"""
return a + b
if __name__ == '__main__':
import doctest
doctest.testmod()
Running Doctests
To run the doctests, save the code example above as a Python file (e.g., my_module.py
). Then, execute the file from your terminal using the command python my_module.py -v
. The -v
flag (verbose) provides detailed output, showing each test case and whether it passed or failed. Without the -v
flag, you'll only see output if a test fails.
# Save the code above as 'my_module.py'
# Run in the terminal:
# python my_module.py -v
Concepts Behind the Snippet
The core idea behind doctests is to embed tests directly into the documentation. This has several benefits: Doctests rely on Python's
doctest
module, which parses the docstrings, identifies the test cases, executes the code, and compares the output.
Real-Life Use Case
Consider a function that formats names. Instead of writing separate unit tests, you can include doctests directly in the function's docstring. This makes it clear how the function is intended to be used and provides immediate verification that it works as expected.
def format_name(first_name, last_name):
"""Formats a name into 'Last Name, First Name' format.
>>> format_name('John', 'Doe')
'Doe, John'
>>> format_name('Alice', 'Smith')
'Smith, Alice'
"""
return f'{last_name}, {first_name}'
Best Practices
-v
Flag: When running doctests, use the -v
flag to get detailed output and verify that all tests are passing.
Interview Tip
When asked about testing strategies, mentioning doctests demonstrates a good understanding of simple testing methodologies that integrate with documentation. It shows you care about code quality and documentation. You can explain the benefits of doctests, like ease of use and integrated documentation/testing.
When to use them
Use doctests when you want to: Avoid doctests for:
Memory Footprint
Doctests have a minimal memory footprint. Each test case is executed independently, and the results are compared directly. The doctest
module itself has a small overhead.
Alternatives
Alternatives to doctests include:
unittest
: A more comprehensive testing framework for complex tests.pytest
: Another popular testing framework with a simpler syntax and extensive plugin ecosystem.nose2
: An alternative to unittest
with improved discovery and plugin support.
Pros
Cons
FAQ
-
How do I handle exceptions in doctests?
You can test for exceptions using the
doctest.EXPECT_EXCEPTION
flag or by including the expected exception type in the output:>>> 1 / 0 # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... ZeroDivisionError: division by zero
Or you can directly expect the exception to occur:
>>> raise ValueError("Invalid value") # doctest: +EXPECT_EXCEPTION Traceback (most recent call last): ...ValueError: Invalid value
-
Can I ignore whitespace differences in doctests?
Yes, you can use the
doctest.NORMALIZE_WHITESPACE
flag when running the tests. This flag ignores differences in whitespace when comparing the actual output with the expected output.import doctest import my_module # Replace with your module name doctor = doctest.DocTestFinder().find(my_module)[0] doctor.options[doctest.NORMALIZE_WHITESPACE] = True if __name__ == '__main__': doctest.testmod(verbose=True)
-
How do I test functions that produce random output?
Testing functions that produce random output can be tricky. You can use the
doctest.ELLIPSIS
flag to ignore parts of the output that vary. Alternatively, you can mock the random number generator to produce predictable results.>>> import random >>> random.random() # doctest: +ELLIPSIS 0.123...