【问题标题】:Why does this doctest pass in Pycharm, but not on the command line?为什么这个 doctest 在 Pycharm 中通过,而不是在命令行中?
【发布时间】:2021-09-15 21:28:50
【问题描述】:

我在 Python 3.9 文档测试中遇到了一个非常奇怪的单元测试失败。通常我必须清理我的问题,但这是在相当低级的代码中,所以我可以将其全部发布在这里。

我可以毫无问题地在 Pycharm 中运行这个 doctest。当我在命令行上运行它时,我得到了一个毫无意义的失败。任何帮助将不胜感激。

quadratic_solver.py

import math
import numpy as np
import doctest


def solve(
        a: float,
        b: float,
        c: float):
    """
    :return: the roots of the quadratic arranged in a 0-2 floating point value-long array

    >>> roots = solve(2., -1., 100.) # noRoots
    >>> len(roots)
    0
    >>> roots = solve(1., 2., 1.) # oneRoot
    >>> len(roots)
    1
    >>> round(roots[0], 9)
    -1.0
    >>> roots = solve(1., 4., 1.) # twoRoots_1
    >>> len(roots)
    2
    >>> round(roots[0], 9)
    -3.732050808
    >>> round(roots[1], 9)
    -0.267949192
    >>> roots = solve(-9., 61., 19.) # twoRoots_2
    >>> len(roots)
    2
    >>> round(roots[0], 9)
    -0.298343001
    >>> round(roots[1], 9)
    7.076120779
    """
    # https://math.stackexchange.com/questions/866331/numerically-stable-algorithm-for-solving-the-quadratic-equation-when-a-is-very
    desc = b**2 - 4. * a * c
    if desc < 0.:
        # no roots
        return np.array([])
    elif desc == 0.:
        # one root
        root = -b / (2. * a)
        return np.array([root])
    else:
        d = math.sqrt(b**2 - 4. * a * c)

        root1 = (-b + d) / (2. * a)
        root2 = (-b - d) / (2. * a)

        if root1 < root2:
            return np.array([root1, root2])
        else:
            return np.array([root2, root1])


doctest.testmod()

运行python -m doctest $PATH_TO_FILE$/quadratic_solver.py时的错误信息:

**********************************************************************
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1820, in __main__.DebugRunner
Failed example:
    runner.run(test)
Expected:
    Traceback (most recent call last):
    ...
    doctest.UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
Got:
    Traceback (most recent call last):
      File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1336, in __run
        exec(compile(example.source, filename, "single",
      File "<doctest __main__.DebugRunner[15]>", line 1, in <module>
        runner.run(test)
      File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1844, in run
        r = DocTestRunner.run(self, test, compileflags, out, False)
      File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1483, in run
        return self.__run(test, compileflags, out)
      File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1388, in __run
        self.report_unexpected_exception(out, test, example,
      File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/doctest.py", line 1850, in report_unexpected_exception
        raise UnexpectedException(test, example, exc_info)
    UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
**********************************************************************

【问题讨论】:

  • 您是否从两者运行相同版本的python?你在 PyCharm 中使用 venv 吗?我猜您正在运行 2 个不同的版本,其中一个缺少软件包。
  • 这是个好问题。我只是仔细检查了一下,我的 PyCharm 解释器设置为在命令行上处于活动状态的相同 venv。
  • Pycharm 真正做的就是运行一个命令行命令,其实你也许能看到。如果你真的是从同一个位置执行同一个命令,输出会是一样的。
  • 这是命令(我替换了路径以缩短响应) $venv$/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm/docrunner.py $path_to_file$ /quadratic_solver.py 和我的命令不完全一样,看起来 PyCharm 地里有一个辅助脚本。我仍然想知道为什么命令行说这很糟糕......

标签: python unit-testing pycharm python-3.9 doctest


【解决方案1】:

这里的问题是doctest.testmod()这一行。

PyCharm 只是检测到 Python 模块中有 doctest,并使用自己的 doctest runner 运行它们,所以它只是忽略该行。

如果您从命令行调用 doctester,它的作用基本相同:它检测所有 doctests 并运行它们,另外它还尝试对 doctest 执行行进行 doctest。如果您使用详细输出,您可以看到这一点:

python -m doctest -v $PATH_TO_FILE$/quadratic_solver.py

这表明所有的文档测试都正确运行,然后doctest 中的测试被执行。 doctest 中的一个类(即DebugRunner)本身有一个失败的文档测试(不确定这是一个错误,还是不打算以这种方式运行)。

这样做的原因是,如果通过库调用(使用 if __name__ == "__main__"),在这种情况下来自 doctester,您不会保护测试运行程序代码不被执行。

因此,要解决此问题,您有两种可能性:

  • 删除调用文档测试的行;这将使它在命令行上与 doctest 一起工作
  • 使用:
if __name__ == "__main__":
    doctest.testmod()

这将使它与通过 doctest 的调用一起工作:

python -m doctest $PATH_TO_FILE$/quadratic_solver.py

以及只执行模块中 doctest 行的调用:

python $PATH_TO_FILE$/quadratic_solver.py

请注意,第二个变体也适用于您当前的代码,但这也意味着每当您从其他地方导入库时都会执行 doctest,您当然不希望这样做。

【讨论】:

  • 谢谢!我删除了对 doctest.testmod() 的调用,一切正常。非常感谢您的帮助。
猜你喜欢
  • 2016-02-06
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
  • 2012-05-11
  • 1970-01-01
  • 2022-11-07
相关资源
最近更新 更多