我尝试在Python 2.7程序的类StringIO
中的doctest中使用实例。我没有从测试中获得任何输出,而是得到了一个响应,“什么也没有”。
这个简化的测试案例展示了该错误:
#!/usr/bin/env python2.7
# encoding: utf-8
class Dummy(object):
'''Dummy: demonstrates a doctest problem
>>> from StringIO import StringIO
... s = StringIO()
... print("s is created")
s is created
'''
if __name__ == "__main__":
import doctest
doctest.testmod()
预期的行为:通过测试。
观察到的行为:测试失败,输出如下:
% ./src/doctest_fail.py
**********************************************************************
File "./src/doctest_fail.py", line 7, in __main__.Dummy
Failed example:
from StringIO import StringIO
s = StringIO()
print("s is created")
Expected:
s is created
Got nothing
**********************************************************************
1 items had failures:
1 of 1 in __main__.Dummy
***Test Failed*** 1 failures.
为什么此doctest失败?为了能够在我的doctest中使用类似StringIO的功能(具有文件接口的文字字符串),我需要进行哪些更改?
[以wim的正确答案为基础,但通过查看底层doctest
语义来解释其中的原因。]
该示例失败,因为它在单独的简单语句之前使用PS2语法(...
)而不是PS1语法(>>>
)。
更改...
为>>>
:
#!/usr/bin/env python2.7
# encoding: utf-8
class Dummy(object):
'''Dummy: demonstrates a doctest problem
>>> from StringIO import StringIO
>>> s = StringIO()
>>> print("s is created")
s is created
'''
if __name__ == "__main__":
import doctest
doctest.testmod()
现在,更正后的示例已重命名为doctest_pass.py
,可以正确运行。它不产生输出,意味着所有测试都通过:
% src/doctest_pass.py
为什么>>>
语法正确?适用于doctest的Python库参考25.2.3.2。Docstring示例如何识别?应该是找到答案的地方,但是对于这种语法尚不十分清楚。
Doctest扫描文档字符串,查找“示例”。在它看到PS1字符串的地方>>>
,以从那里到该行结尾的所有内容为例。它还将以PS2字符串开头的以下任何行附加...
到示例(请参阅:_EXAMPLE_RE
在类中doctest.DocTestParser
,行584-595)。它将后续的行,直到下一个空行或以PS1字符串开头的行作为通缉输出。
文档测试编译每个实施例为Python“互动语句”,使用compile()
内置函数在exec
声明(参见:doctest.DocTestRunner.__run()
,线1314至1315年)。
“交互式语句”是以换行符或“复合语句”结尾的语句列表。复合语句,例如if
ortry
语句,“一般来说,[…跨越]多行,尽管在简单的形式中,整个复合语句可以包含在一行中。” 这是多行复合语句:
if 1 > 0:
print("As expected")
else:
print("Should not happen")
语句列表是一行中的一个或多个简单语句,以分号分隔。
from StringIO import StringIO
s = StringIO(); print("s is created")
因此,问题的doctest失败了,因为它包含一个包含三个简单语句的示例,并且没有分号分隔符。将PS2字符串更改为PS1字符串成功,因为它将文档字符串转换为三个示例的序列,每个示例都有一个简单的语句。尽管这三行代码可以一起对一项功能进行测试,但它们并不是单个测试夹具。它们是三个测试,其中两个设置状态,但并未真正测试主要功能。
顺便说一句,您可以看到doctest
使用-v
标志识别的示例数。请注意,它说:“ 3 tests in __main__.Dummy
”。人们可能会将三行视为一个测试单元,但会doctest
看到三个示例。前两个示例没有预期的输出。当示例执行且不生成任何输出时,将被视为“通过”。
% src/doctest_pass.py -v
Trying:
from StringIO import StringIO
Expecting nothing
ok
Trying:
s = StringIO()
Expecting nothing
ok
Trying:
print("s is created")
Expecting:
s is created
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.Dummy
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
在单个文档字符串中,示例按顺序执行。每个示例的状态更改将在同一文档字符串中保留以下示例的状态。因此,该import
语句定义模块名称,s =
赋值语句使用该模块名称并定义变量名称,依此类推。doctest文档,25.2.3.3。什么是执行上下文?,当说“示例可以自由使用…在运行的文档字符串中更早定义的名称”时,倾斜地公开了这一点。
该节中的前面的句子是:“每次doctest都找到一个要测试的文档字符串,它使用M的全局变量的浅表副本,因此…M中的一个测试不能留下偶然允许另一个测试起作用的碎屑”。有点误导。的确,M中的一个测试不会影响其他文档字符串中的测试。但是,在单个文档字符串中,较早的测试肯定会留下碎屑,这很可能会影响以后的测试。
为什么在Python库参考中的doctest 25.2.3.2。Docstring示例如何识别?,显示...
语法示例?该示例显示一条if
语句,它是多行上的复合语句。第二行和后续行用PS2字符串标记。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句