如何testing或模拟“如果__name__ =='__main__'”的内容

假设我有一个与以下模块:

def main(): pass if __name__ == "__main__": main() 

我想写一个下半部的unit testing(我想达到100%的覆盖率)。 我发现执行import / __name__机制的runpy builtin模块,但是我不知道如何模拟或者检查main()函数是否被调用。

这是我迄今为止所尝试的:

 import runpy import mock @mock.patch('foobar.main') def test_main(self, main): runpy.run_module('foobar', run_name='__main__') main.assert_called_once_with() 

我将select另一个替代方法,即从覆盖率报告中排除if __name__ == '__main__' ,当然,只有在testing中已经有main()函数的testing用例时,才可以这样做。

至于为什么我select排除而不是为整个脚本编写一个新的testing用例是因为如果我说你已经有了一个main()函数的testing用例,那么你为脚本添加了另外一个testing用例有100%的覆盖率)将只是一个重复的。

关于如何排除if __name__ == '__main__'你可以编写一个覆盖configuration文件,并添加到部分报告中:

 [report] exclude_lines = if __name__ == .__main__.: 

有关覆盖configuration文件的更多信息可以在这里find。

希望这可以帮助。

您可以使用imp模块而不是import语句来执行此操作。 import语句的问题是,在你有机会分配给runpy.__name__之前,' runpy.__name__ '__main__'testing作为import语句的一部分运行。

例如,你可以像这样使用imp.load_source()

 import imp runpy = imp.load_source('__main__', '/path/to/runpy.py') 

第一个参数分配给导入模块的__name__

哇,我晚了一点,但我最近遇到这个问题,我想我想出了一个更好的解决scheme,所以这里是…

我正在研究一个包含十几个脚本的模块,所有这些脚本都以这个完全相同的副本结束:

 if __name__ == '__main__': if '--help' in sys.argv or '-h' in sys.argv: print(__doc__) else: sys.exit(main()) 

不可怕,当然,但也不可testing。 我的解决scheme是在我的一个模块中写一个新的函数:

 def run_script(name, doc, main): """Act like a script if we were invoked like a script.""" if name == '__main__': if '--help' in sys.argv or '-h' in sys.argv: sys.stdout.write(doc) else: sys.exit(main()) 

然后将这个gem放在每个脚本文件的末尾:

 run_script(__name__, __doc__, main) 

从技术上讲,无论您的脚本是作为模块导入还是作为脚本运行,都将无条件地运行此function。 这是可以的,但是因为这个函数实际上并没有任何事情,除非这个脚本是作为脚本运行的。 所以代码覆盖看到函数运行,并说“是的,100%的代码覆盖率!” 同时,我写了三个testing来涵盖这个函数本身:

 @patch('mymodule.utils.sys') def test_run_script_as_import(self, sysMock): """The run_script() func is a NOP when name != __main__.""" mainMock = Mock() sysMock.argv = [] run_script('some_module', 'docdocdoc', mainMock) self.assertEqual(mainMock.mock_calls, []) self.assertEqual(sysMock.exit.mock_calls, []) self.assertEqual(sysMock.stdout.write.mock_calls, []) @patch('mymodule.utils.sys') def test_run_script_as_script(self, sysMock): """Invoke main() when run as a script.""" mainMock = Mock() sysMock.argv = [] run_script('__main__', 'docdocdoc', mainMock) mainMock.assert_called_once_with() sysMock.exit.assert_called_once_with(mainMock()) self.assertEqual(sysMock.stdout.write.mock_calls, []) @patch('mymodule.utils.sys') def test_run_script_with_help(self, sysMock): """Print help when the user asks for help.""" mainMock = Mock() for h in ('-h', '--help'): sysMock.argv = [h] run_script('__main__', h*5, mainMock) self.assertEqual(mainMock.mock_calls, []) self.assertEqual(sysMock.exit.mock_calls, []) sysMock.stdout.write.assert_called_with(h*5) 

布拉姆! 现在,您可以编写一个可testing的main() ,将其作为脚本调用,具有100%的testing覆盖率,并且不需要忽略覆盖率报告中的任何代码。

一种方法是将模块作为脚本运行(例如os.system(…)),并将其stdout和stderr输出与期望值进行比较。