Latest update Android YouTube

doctest | Testing in Python

Python Testing: doctest (Complete Guide)

Mastering inline documentation tests for executable specifications

1. doctest: Inline Testing

Basic Syntax & Execution

def add(a, b):
    """
    Adds two numbers.
    
    >>> add(2, 3)
    5
    >>> add(-1, 1)
    0
    """
    return a + b
python -m doctest module.py Run tests (silent unless failures)
python -m doctest -v module.py Verbose output (show all tests)
python -m doctest *.txt Test standalone text files

Advanced Formatting

def format_data(data):
    """
    >>> format_data(['a', 'b'])  # doctest: +NORMALIZE_WHITESPACE
    ['a',
     'b']
     
    >>> import random
    >>> random.random()  # doctest: +ELLIPSIS
    0...
    
    >>> print("First line\\n\\nThird line")  # doctest: +REPORT_NDIFF
    First line
    
    Third line
    """
    return data

Edge Cases

def divide(a, b):
    """
    >>> divide(1.0, 3.0)  # doctest: +ELLIPSIS
    0.333...
    
    >>> import datetime
    >>> datetime.datetime.now()  # doctest: +SKIP
    datetime.datetime(2023, 1, 1, 12, 0)
    
    >>> 1 / 0
    Traceback (most recent call last):
    ZeroDivisionError: division by zero
    """
    return a / b

2. doctest: Documentation Tests

Best Practices

  • Keep docstring examples realistic and readable
  • Place basic usage examples first, edge cases after
  • Use doctest for API examples, unittest/pytest for complex scenarios

Integration Methods

project/
├── module.py # Module-level doctests
├── tests/
│ ├── doctests/ # Standalone .txt files
│ └── test_doctest.py # unittest integration

Execution Control

Directive Purpose
# doctest: +SKIP Skip this test
# doctest: +ELLIPSIS Enable ... wildcard matching
# doctest: +NORMALIZE_WHITESPACE Ignore whitespace differences
# doctest: +IGNORE_EXCEPTION_DETAIL Match exceptions loosely

3. Advanced doctest Features

Test Fixtures

def setup_test():
    """
    >>> import tempfile
    >>> fd, path = tempfile.mkstemp()
    >>> with open(path, 'w') as f:
    ...     _ = f.write("test data\\n")
    >>> # Test code using the temp file
    >>> import os
    >>> os.remove(path)
    """
    pass

Customization

from doctest import DocTestRunner, OutputChecker

class MyOutputChecker(OutputChecker):
    def check_output(self, want, got, optionflags):
        # Custom comparison logic
        return super().check_output(want, got, optionflags)

runner = DocTestRunner(checker=MyOutputChecker())

Performance Considerations

  • Use doctest.testmod(verbose=False) in production
  • Move complex tests to separate files
  • Skip computationally expensive examples

4. Real-World Patterns

Documentation-Driven Development

def sort_items(items):
    """
    Sorts items according to business rules.
    
    Specification Example:
    >>> sort_items([3, 1, 2])
    [1, 2, 3]
    
    Real-world Usage:
    >>> data = load_production_data()
    >>> results = sort_items(data)  # doctest: +SKIP
    >>> assert len(results) == len(data)  # doctest: +SKIP
    """
    return sorted(items)

Debugging Techniques

def failing_function():
    """
    >>> failing_function()  # Expected: 42
    24
    """
    return 24

if __name__ == "__main__":
    import doctest
    doctest.testmod()  # Run with -v to see failures

5. Limitations & Alternatives

When Not to Use Doctest

  • Complex test setups requiring fixtures
  • Data-driven tests with many variations
  • Performance benchmarking
  • UI or integration tests

Complementary Tools

# unittest integration example
import unittest
import doctest
import mymodule

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(mymodule))
    return tests

Integration Tip: Combine doctest with pytest using pytest --doctest-modules to run both doctests and regular tests together.

6. Complete Example

def factorial(n):
    """
    Compute the factorial of n.
    
    Examples:
    >>> factorial(3)
    6
    >>> factorial(5)
    120
    
    Edge cases:
    >>> factorial(0)
    1
    >>> factorial(-1)
    Traceback (most recent call last):
    ValueError: n must be >= 0
    
    Floating point approximation:
    >>> factorial(20.0)  # doctest: +ELLIPSIS
    2.43290200...e+18
    
    Documentation example:
    >>> print("5! =", factorial(5))
    5! = 120
    """
    if n < 0:
        raise ValueError("n must be >= 0")
    return 1 if n == 0 else n * factorial(n-1)

if __name__ == "__main__":
    import doctest
    doctest.testmod(verbose=True)

Performance Warning: For recursive functions like factorial, consider adding a # doctest: +SKIP directive for very large values to avoid slowing down documentation builds.

Post a Comment

Feel free to ask your query...
Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.