7

我有一个 Python 包(Python 3.6,如果有区别的话),我设计为作为“python -m 参数”运行,我想为 __main__.py 模块编写单元测试。我特别想验证它是否正确设置了退出代码。是否可以使用 runpy.run_module 执行我的 __main__.py 并测试退出代码?如果是这样,我如何检索退出代码?

更清楚地说,我的 __main__.py 模块非常简单。它只是调用一个已经过广泛单元测试的函数。但是当我最初编写 __main__.py 时,我忘记了将该函数的结果传递给 exit(),所以我希望在单元测试中模拟主函数以确保正确设置退出代码。我的单元测试看起来像:

@patch('my_module.__main__.my_main', return_value=2)
def test_rc2(self, _):
    """Test that rc 2 is the exit code."""
    sys.argv = ['arg0', 'arg1', 'arg2', …]
    runpy.run_module('my_module')
    self.assertEqual(mod_rc, 2)

我的问题是,我怎样才能得到我在这里写的“mod_rc”?

谢谢。

4

3 回答 3

4

Misko Hevery 之前说过(我相信是在Clean Code Talks: Don't Look for Things但我可能错了)他不知道如何有效地对主要方法进行单元测试,所以他的解决方案是让它们变得如此简单如果您假设他们调用的(经过单元测试的)代码的正确性,您可以从逻辑上证明它们有效。

例如,如果您有一个离散的、经过测试的单元来解析命令行参数;做实际工作的图书馆;以及一个离散的、经过测试的单元,用于将完成的工作渲染为输出,然后一个按顺序调用所有这三个的主要方法肯定会起作用。

使用这种架构,您基本上可以只进行一个大型系统测试,该测试预计会产生除“默认”输出之外的其他内容,并且它会崩溃(因为您连接不正确)或工作(因为它连接正确)并且所有单独的部分都可以工作)。


在这一点上,我放弃所有假装知道我在说什么。几乎可以肯定有更好的方法来做到这一点,但坦率地说,你可以写一个 shell 脚本:

python -m package args
test $? -eq [expected exit code]

这将退出iff您的程序输出不正确的错误,TravisCI 或类似的将视为构建失败。

于 2018-03-21T17:46:44.053 回答
1

__main__.py仍然受制于正常的__main__全局行为——也就是说,你可以__main__.py像这样实现你的

def main():
  # Your stuff

if __name__ == "__main__":
  main()

然后你可以__main__使用任何你喜欢的测试框架来测试你的

from your_package.__main__ import main

顺便说一句,如果您正在使用argparse,您可能会想要:

def main(arg_strings=None):
  # …
  args = parser.parse_args(arg_strings)
  # …

if __name__ == "__main__":
  main()

然后你可以简单地覆盖单元测试中的arg字符串

from your_package.__main__ import main

def test_main():
  assert main(["x", "y", "z"]) == …

或您测试框架中的类似习语。

于 2021-12-15T20:56:56.940 回答
0

使用 pytest,我能够做到:

import mypkgname.__main__ as rtmain

其中 mypkgname 是您将应用程序命名为包/模块的名称。然后正常运行 pytest 即可。我希望这可以帮助其他一些可怜的灵魂。

于 2020-06-19T18:01:10.083 回答