5

如何让我的(Python 2.7)代码知道它是否在 doctest 中运行?

场景如下:我有一个函数,它print()输出到作为参数传入的文件描述符,如下所示:

from __future__ import print_function

def printing_func(inarg, file=sys.stdout):
    # (do some stuff...)
    print(result, file=file)

但是当我尝试printing_func()在 doctest 中使用时,测试失败了;由于我file在调用时指定了关键字参数print(),因此输出实际上会转到sys.stdout而不是 doctest 模块设置的任何默认输出重定向,并且 doctest 永远不会看到输出。

那么我怎样才能printing_func()知道它是否在 doctest 中运行,以便它知道file在调用时不传递关键字参数print()呢?

4

4 回答 4

4

Niten 的版本inside_doctest似乎过于宽泛。重新定义 并不少见sys.stdout,无论是用于日志记录还是在 doctest 以外的框架中进行测试时,都会产生误报。

更窄的测试如下所示:

import sys

def in_doctest():
    """
Determined by observation
    """
    if '_pytest.doctest' in sys.modules:
        return True
    ##
    if hasattr(sys.modules['__main__'], '_SpoofOut'):
        return True
    ##
    if sys.modules['__main__'].__dict__.get('__file__', '').endswith('/pytest'):
        return True
    ##
    return False


def test():
    """
    >>> print 'inside comments, running in doctest?', in_doctest()
    inside comments, running in doctest? True
    """
    print 'outside comments, running in doctest?', in_doctest()

if __name__ == '__main__':
    test()

in_doctest测试_SpoofOut类 doctest 用于替换sys.stdout. doctest 模块的其他属性可以以相同的方式进行验证。并不是说您可以阻止另一个模块重用名称,但是这个名称并不常见,因此可能是一个不错的测试。

将上面的内容放在 test.py 中。在非 doctest 模式下运行它,python test.py产生:

outside comments, running in doctest? False

在 doctest 详细模式下运行,python -m doctest test.py -v产生:

Trying:
    print 'inside comments, running in doctest?', in_doctest()
Expecting:
    inside comments, running in doctest? True
ok

我同意其他人的评论,即让代码了解 doctest 通常是一个坏主意。我只是在有些奇怪的情况下才这样做——当我需要通过代码生成器创建测试用例时,因为有太多无法有效地手动制作。但是如果你需要这样做,上面是一个不错的测试。

于 2014-03-29T17:41:19.303 回答
1

看完后我想出了答案doctest.py;在这里张贴给后代...

Doctest 通过将新的文件描述符分配给sys.stdout. 问题是我的函数描述在 doctest 重新定义之前关闭了原始sys.stdout文件描述符的值。

相反,如果我执行以下操作:

def printing_func(inarg, file=None):
    # (do some stuff...)

    if file is None:
        file = sys.stdout

    print(result, file=file)

thenprinting_func()将捕获sys模块而不是sys.stdout,并且当它运行时,如果在测试中运行,它将检索 doctest 的重新定义stdout属性sys

编辑:这也产生了一种简单的方法来检查我们是否在 doctest 中运行:

def inside_doctest(original_stdout=sys.stdout):
    return original_stdout != sys.stdout
于 2011-11-14T01:06:42.560 回答
0

FWIW(很抱歉迟到和多余)许多开发人员将“if test”视为反模式。

即,如果您的被测代码在被测试时与“真正”运行时做的事情不同,那么您就是在自找麻烦。即使你相信你这样做是有充分理由的。因此,上面的评论为您没有这样做的解决方案鼓掌。当我想使用“if test”模式时,我会尝试重构一些东西,这样就不需要了。

于 2013-12-14T20:12:41.440 回答
0

我只是检查模块“doctest”是否已加载。

def in_doctest():
    import sys
    return 'doctest' in sys.modules
于 2019-01-16T17:18:55.683 回答