Python 是否有方法只执行doctest,而忽略打印函数调用?

Python 是否有方法只执行doctest,而忽略打印函数调用?,python,python-3.x,testing,doctest,Python,Python 3.x,Testing,Doctest,假设地说,我的函数返回一个值,并且有很多打印语句(可能是100或更多) 是否有一种运行方式可以忽略/跳过所有其他打印工作(我熟悉+SKIP指令,该指令用于跳过doctest示例),即当我使用doctests执行函数(或以脚本形式运行模块)时: python mymodule.py 或: 我应该得到: 如果成功,什么都没有;或 任何测试示例失败时的错误消息 没有别的了。运行doctest不会给我一个终端窗口,里面充满了那些print函数调用的输出/文本 请不要建议使用单元测试(例如),因为它

假设地说,我的函数返回一个值,并且有很多打印语句(可能是100或更多)

是否有一种运行方式可以忽略/跳过所有其他打印工作(我熟悉
+SKIP
指令,该指令用于跳过
doctest
示例),即当我使用
doctest
s执行函数(或以脚本形式运行模块)时:

python mymodule.py
或:

我应该得到:

  • 如果成功,什么都没有;或
  • 任何测试示例失败时的错误消息
没有别的了。运行
doctest
不会给我一个终端窗口,里面充满了那些
print
函数调用的输出/文本


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

doctest
使用
stdout
而不是
stderr
,来显示任何失败测试的消息。因此,您无法按照此答案最初的建议修补
stdout
——这将禁止您的
print
调用
doctest
中的任何消息


一个选项是使用附加的
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')
这也需要更改函数定义,但至少可以避免更改这些函数的主体


第三个选项是为整个测试模块修补
打印
,例如:

def baz():
    """Does whatever.

        >>> baz()

    """
    print('Hello world')

if __name__ == '__main__':

    import doctest

    print = lambda *args, **kwargs: None

    doctest.testmod()
请注意,这也会影响
doctest
看到的输出,因此您不会在docstring中包含任何
print
输出(我认为这是个好消息!)它不会与
python-m doctest mymodule.py一起工作,不过。

除了“非常好的答案”,还有一种方法,这确实适用于
python3-mdoctest 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 doctest


非常好。对于最后一种情况,如何
COMMAND=os.path.splitext(os.path.basename(sys.argv[0]))[0];打印=(lambda*args,**kwargs:None)如果命令==“doctest”else打印
@jcomeau_ictx我会保护重新分配,而不是使用三元表达式,但如果你需要edge case,这会起作用。是的,如果我不想在评论框中键入它,我也会这样做:微笑:'税收就是偷窃。'是政治,应该是流行歌曲或Monty Python引用。因为你一直在寻找被发现的机会。
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!