pythondoctest

Doctest of function with random output


I have a function that prints a somewhat random string to the console, for example:

from random import choice

def hello():
    print(f"Hello {choice(('Guido', 'Raymond'))}!")

Please note that my actual function is more complicated than this. The random part is a request to a database that can either succeed or fail. This means that I cannot initialize a seed to have a constant outcome.

What I have tried is to use the ellipsis, but I also need to add an ugly comment for doctest to recognize it.

def hello():
    """
    >>> hello()  # doctest: +ELLIPSIS
    Hello ...!
    """
    print(f"Hello {choice(('Guido', 'Raymond'))}!")

Is there a better strategy in this situation?

For example, instead of an ellipsis it would be great if I could test that the answer is one between Hello Guido! and Hello Raymond!.


Solution

  • You could use regex: Hello followed by either Guido or Raymond followed by an exclamation point and newline: Hello (Guido|Raymond)!\n

    However, capturing the stdout and running the regex is a lot of noise for a doctest. So instead, it'd be better to give an example in the docstring but skip testing it, and use a different test system, like pytest, which has a builtin way to capture stdout. For example:

    from random import choice
    
    def hello():
        """
        >>> hello()  # doctest: +SKIP
        Hello Raymond!
        """
        print(f"Hello {choice(('Guido', 'Raymond'))}!")
    
    import re
    
    def test_hello(capsys):
        hello()
        captured = capsys.readouterr()
        assert re.fullmatch(r'Hello (Guido|Raymond)!\n', captured.out)