有没有办法只执行文档测试,而忽略打印函数调用?

Is there way to only perform the doctests, ignoring print function calls?

假设地说,我的函数 returns 一个值 有很多打印语句 (可能有 100 个或更多)。

有没有办法运行 doctest 使得所有其他打印工作都可以ignored/skipped(我熟悉+SKIP指令,这是为了跳过 doctest 示例),即当我使用 doctests:

执行我的函数(或 运行 我的模块作为脚本)时
python mymodule.py

或者:

python -m doctest mymodule.py

我应该得到:

仅此而已。 运行 doctest 不应该给我一个终端 window 充满那些 print 函数调用的输出/文本。

请不要建议使用单元测试(例如 unittest),因为它会扼杀问题的本质。

doctest 使用 stdout 而不是 stderr 来显示任何失败测试的消息。因此,您不能像最初建议的那样修补 stdout - 这将抑制您的 print 调用 来自 doctest.[=26= 的任何消息]


一个选项是定义 print 带有附加 verbose 参数的函数,以便您可以在必要时抑制它。

def foo(verbose=True):
    """Does whatever.

        >>> foo(verbose=False)

    """
    if verbose:
        print('Hello world')

虽然您必须更改功能,但这也为您在不测试时提供了有用的选项。


另一种方法是向使用它的函数显式提供适当的 print 函数,允许您在运行时传递 NOOP:

def bar(print=print):
    """Does whatever.

        >>> bar(print=lambda *args, **kwargs: None)

    """
    print('Hello world')

这也需要更改函数定义,但至少可以避免更改这些函数的 bodies


第三个选项是为整个被测模块修补 print,例如:

def baz():
    """Does whatever.

        >>> baz()

    """
    print('Hello world')

if __name__ == '__main__':

    import doctest

    print = lambda *args, **kwargs: None

    doctest.testmod()

请注意,这也会影响 doctest 看到的输出,因此您不要在文档字符串中包含任何 print 输出(我认为这是个好消息!)它赢了不过,请使用 python -m doctest mymodule.py

除了 jonrsharpe 的出色答案之外,还有另一种方法,即 python3 -m doctest module.py 结构一起工作。

#!/usr/bin/python3 -OO
'''
Some ideas for adding additional verbosity during doctest, and for
reducing verbosity and startup delays during doctest or pydoc.
'''
from __future__ import print_function  # for compatibility with python2
import sys, os, logging
logging.basicConfig(level = logging.DEBUG if __debug__ else logging.INFO)
COMMAND = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if COMMAND in ['doctest', 'pydoc']:
    NONDOCTESTPRINT = lambda *args, **kwargs: None
    DOCTESTDEBUG = logging.debug
else:
    NONDOCTESTPRINT = print
    DOCTESTDEBUG = lambda *args, **kwargs: None
    # You can also use this `else` block to import things not needed during
    # doctest, especially slow-loading modules like `requests`,
    # or to do some other verbose or slow initialization.

def test(string):
    '''
    print string after lead-in

    >>> test("I'm in love with you!")
    Listen!
    I'm in love with you!
    '''
    DOCTESTDEBUG("If this works, you shouldn't see anything but this")
    print('Listen!')
    NONDOCTESTPRINT('Do you want to know a secret?')
    NONDOCTESTPRINT('Do you promise not to tell? Whoa, oh...')
    NONDOCTESTPRINT('Closer...')
    NONDOCTESTPRINT('Let me whisper in your ear...')
    NONDOCTESTPRINT('Say the words you long to hear...')
    print(string)

if __name__ == '__main__':
    test(' '.join(sys.argv[1:]) or 'Taxation is theft.')

这是输出的样子,具体取决于它的调用方式。

jcomeau@aspire:/tmp$ python3 -m doctest doctesttest.py 
DEBUG:root:If this works, you shouldn't see anything but this
jcomeau@aspire:/tmp$ python3 doctesttest.py This is a test!
Listen!
Do you want to know a secret?
Do you promise not to tell? Whoa, oh...
Closer...
Let me whisper in your ear...
Say the words you long to hear...
This is a test!

pydoc doctesttest