我尝试在我的类中的StringIO
中使用doctest实例,在Python 2.7程序中。我没有从测试中获得任何输出,而是得到了回复,而没有得到任何结果#34;。
这个简化的测试用例演示了错误:
#!/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失败了?为了能够在我的doctests中使用类似StringIO的功能(带文件接口的文字字符串),我需要做些什么改变?
答案 0 :(得分:5)
这是令人困惑的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()
答案 1 :(得分:1)
[建立在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. How are Docstring Examples Recognized?应该是找到答案的地方,但对于这种语法并不十分清楚。
Doctest扫描文档字符串,查找“示例”。在它看到PS1字符串>>>
的地方,它将从那里到行尾的所有内容作为示例。它还会将以PS2字符串...
开头的任何后续行追加到示例中(请参阅类_EXAMPLE_RE
中的doctest.DocTestParser
,第584-595行)。它采用后续行,直到下一个以PS1字符串开头的空白行或行,作为通缉输出。
Doctest使用compile()
中的exec
statement内置函数将每个示例编译为Python“交互式语句”(参见:doctest.DocTestRunner.__run()
,第1314-1315行)。
“interactive statement”是以换行符或Compound Statement结尾的语句列表。复合语句,例如if
或try
语句,“一般来说,[......跨越]多行,尽管在简单的化身中,整个复合语句可能包含在一行中。”这是一个多行复合语句:
if 1 > 0:
print("As expected")
else:
print("Should not happen")
语句列表是一行中的一个或多个simple statement,以分号分隔。
from StringIO import StringIO
s = StringIO(); print("s is created")
因此,问题的doctest失败了,因为它包含一个带有三个简单语句的示例,并且没有分号分隔符。将PS2字符串更改为PS1字符串成功,因为它将docstring转换为三个示例的序列,每个示例都有一个简单的语句。虽然这三条线共同设置一个功能的一个测试,但它们不是一个单独的测试夹具。它们是三个测试,其中两个设置状态,但没有真正测试主要功能。
顺便说一下,您可以使用doctest
标志查看-v
识别的示例数。请注意,它说“3 tests in __main__.Dummy
”。有人可能会认为这三行是一个测试单元,但是doctest
看到了三个例子。前两个例子没有预期的输出。当Example执行并且不生成输出时,它将被视为“通过”。
% 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. What’s the Execution Context?在它说“实例可以自由使用...之前定义的文档字符串中运行的名称时”倾斜地公开了这一点。
该部分的前一句话,“每次doctest找到要测试的文档字符串时,它都使用M的全局变量的浅层副本,这样...... M中的一个测试不能留下意外允许另一个测试工作的面包屑” ,有点误导。确实,M中的一个测试不会影响另一个文档字符串中的测试 。但是,在单个文档字符串中,较早的测试肯定会留下碎屑,这可能会影响以后的测试。
为什么doctest的Python库参考中的示例25.2.3.2. How are Docstring Examples Recognized?显示了...
语法的示例?该示例显示了if
语句,该语句是多行的复合语句。第二行和后续行标有PS2字符串。