【问题标题】:Python doctest: skip a test conditionallyPython doctest:有条件地跳过测试
【发布时间】:2017-03-10 01:56:18
【问题描述】:

我知道如何使用# doctest: +SKIP 跳过文档测试,但我不知道如何根据运行时条件有时跳过测试。例如:

>>> if os.path.isfile("foo"):
...    open("foo").readlines()
... else:
...    pass # doctest: +SKIP
['hello', 'world']

这就是我想做的事情。我也会接受一个运行测试的解决方案,但如果条件不满足,则将预期结果更改为带有回溯的异常(即无条件运行测试但修改预期结果)。

【问题讨论】:

  • 为了进行正确的测试,您应该可以控制foo 是否存在,让您可以 100% 确定输出应该是什么。
  • @chepner:我有一套不同的机器来运行我的大型测试套件。一些测试需要一些特定机器上不存在的大文件。我无法控制foo 是否存在,仅仅是因为无法将它部署到某些特定的机器上。如果您愿意,我可以将要求改写为“忽略已知无法运行的特定机器上的特定测试用例。”
  • @JohnZwinck,你在这方面有什么进展吗?我会很感兴趣的。
  • @JonasAdler:不,这基本上是不可能的。你可以使用一些愚蠢的技巧,比如编写一个包装函数,它可以做任何你想做的事情,如果它通过(或者如果测试被跳过)则返回 True。
  • 你如何运行你的测试套件?如果您使用的是unittest,详见此处:docs.python.org/2/library/doctest.html#unittest-api,您可以更好地控制执行或不执行哪些测试以及何时执行。

标签: python doctest


【解决方案1】:

如果您不想测试输出,可以返回一个特殊值。让我们调用_skip这个特殊值:

  • 如果设置了适当的标志并且你得到的值是_skip,那么无论预期如何,测试都是成功的
  • 否则(即没有标志或正常返回值),照常执行测试。

你需要一个自定义的OutputChecker

_skip = object()
COND_SKIP = doctest.register_optionflag('COND_SKIP')

class CondSkipChecker(doctest.OutputChecker):
    def check_output(self, want, got, optionflags):
        if optionflags & COND_SKIP and got.strip() == str(_skip):
            return True
        else:
            return super(CondSkipChecker, self).check_output(want, got, optionflags)

这是一个概念证明(doctest API 有点麻烦:人们喜欢将testmod̀checker 参数一起使用):

"""
>>> 1 if True else _skip
2
>>> 1 if False else _skip
2
>>> 1 if True else _skip # doctest: +COND_SKIP
2
>>> 1 if False else _skip # doctest: +COND_SKIP
2
"""

import doctest, sys
_skip = object()
COND_SKIP = doctest.register_optionflag('COND_SKIP')

class CondSkipChecker(doctest.OutputChecker):
    def check_output(self, want, got, optionflags):
        if optionflags & COND_SKIP and got.strip() == str(_skip):
            return True
        else:
            return super(CondSkipChecker, self).check_output(want, got, optionflags)

finder = doctest.DocTestFinder()
runner = doctest.DocTestRunner(CondSkipChecker())
m = sys.modules.get('__main__')
for test in finder.find(m, m.__name__):
    runner.run(test)
print(runner.summarize())

输出:

**********************************************************************
File "temp.py", line 2, in __main__
Failed example:
    1 if True else _skip
Expected:
    2
Got:
    1
**********************************************************************
File "temp.py", line 4, in __main__
Failed example:
    1 if False else _skip
Expected:
    2
Got:
    <object object at 0x0033B8A8>
**********************************************************************
File "temp.py", line 6, in __main__
Failed example:
    1 if True else _skip # doctest: +COND_SKIP
Expected:
    2
Got:
    1
**********************************************************************
1 items had failures:
   3 of   4 in __main__
***Test Failed*** 3 failures.
TestResults(failed=3, attempted=4)

没有 doctest 注释的两个测试按预期失败。注意:如果在没有 COND_SKIP 标志的情况下使用 _skip,您可以轻松添加警告。

第三次测试失败(得到1 vs 预期2),但第四次测试成功(得到̀_skip + COND_SKIP vs 一切正常)。

【讨论】:

    【解决方案2】:

    您可以有条件地对文档字符串进行模板化,以便仅在设置了功能标志时它才包含 doctest 夹具:

    def myFunction():
      '''
      >>> if TEST_AVAILABLE:
      ...   do_one_thing
      ... else:
      ...   do_other_thing
      %s
      '''
      ...
    myFunction.__doc__ %= ('''expected result''' if TEST_AVAILABLE else '')
    

    缺点:不适用于Python -O

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-14
      • 2014-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多