"python -m doctest" 忽略不同目录下的同名文件

"python -m doctest" ignores files with same names in different directories

假设我们有两个文件:

fail/stuff.py

"""
>>> True
False
"""

pass/stuff.py

"""
>>> True
True
"""

然后我们 运行 他们都在 doctest:

python -m doctest fail/stuff.py pass/stuff.py

正如预期的那样,我们看到来自 fail/stuff.py 的错误。但是如果我们 运行 它们的顺序相反:

python -m doctest pass/stuff.py fail/stuff.py

那就过去了!

Python 的导入系统无法处理来自两个文件的加载测试是否有一些根本原因,或者 doctest 只是被破坏了?

在一个Python进程中只能有一个同名的顶级模块,python -m doctest将所有传递给它的文件都视为顶级模块。导入 pass/stuff.py 会在 stuff 模块的模块缓存中填充一个条目,当 doctest 尝试导入您指定的第二个文件时,导入系统会找到 pass/stuff.py 的条目而不是加载 fail/stuff.py.

他们可以通过多种方式来解决这个问题。例如,可以在不填写 sys.modules 条目的情况下从文件导入模块,但如果这些同名文件也具有同名的不同依赖项,或者如果涉及任何循环导入,则仍然可能失败.他们可以尝试在 运行 测试后回滚 sys.modules 到测试前状态,这会更可靠但效率较低,并且仍然可能因模块不能很好地重新加载而失败。另一种选择是为每个测试生成一个单独的子流程,这将是最可靠但效率最低的。

Is there some fundamental reason why Python's import system is unable to cope with loading tests from both files, or is doctest simply broken?

Doctests 基本上就坏了。 Python 导入系统无法处理这种情况没有根本原因。因此,没有根本原因测试运行程序也不能处理这种情况。我怀疑他们在编写命令行界面时考虑得太多,因为大多数人不会直接将 doctest 用作运行器(相反,将库代码与功能更全的运行器集成并使用 doctest 插件将是更平常)。

您可以使用更好的测试运行器。例如,鼻子(除其他外)不会有这个问题:

$ nosetests pass/stuff.py fail/stuff.py --with-doctest
.F
======================================================================
FAIL: Doctest: stuff
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/doctest.py", line 2199, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for stuff
  File "/private/tmp/fail/stuff.py", line 0, in stuff

----------------------------------------------------------------------
File "/private/tmp/fail/stuff.py", line 2, in stuff
Failed example:
    True
Expected:
    False
Got:
    True


----------------------------------------------------------------------
Ran 2 tests in 0.004s

FAILED (failures=1)