Python unittest.py不';我不能和trace.py玩得很好-为什么?
哇。今晚我发现,使用Python unittest.py不';我不能和trace.py玩得很好-为什么?,python,unit-testing,code-coverage,python-unittest,Python,Unit Testing,Code Coverage,Python Unittest,哇。今晚我发现,使用unittest模块编写的Python单元测试在trace模块下的覆盖率分析中效果不佳。下面是最简单的单元测试,在foobar.py中: import unittest class Tester(unittest.TestCase): def test_true(self): self.assertTrue(True) if __name__ == "__main__": unittest.main() 如果我使用python fooba
unittest
模块编写的Python单元测试在trace
模块下的覆盖率分析中效果不佳。下面是最简单的单元测试,在foobar.py
中:
import unittest
class Tester(unittest.TestCase):
def test_true(self):
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()
如果我使用python foobar.py
运行此命令,我将得到以下输出:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
太好了。现在我还想执行覆盖率测试,所以我使用python-m trace--count-C再次运行它。foobar.py
,但现在我明白了:
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
不,Python,这不好-你没有运行我的测试!似乎在trace
的上下文中运行某种程度上破坏了unittest
的测试检测机制。以下是我想出的(疯狂的)解决方案:
import unittest
class Tester(unittest.TestCase):
def test_true(self):
self.assertTrue(True)
class Insane(object):
pass
if __name__ == "__main__":
module = Insane()
for k, v in locals().items():
setattr(module, k, v)
unittest.main(module)
这基本上是一种变通方法,通过伪造顶级模块的副本来具体化抽象的、不可度量的名称。然后,我可以将该名称传递给unittest.main()
,以避开trace
对其产生的任何影响。无需向您显示输出;它看起来就像上面的成功例子
因此,我有两个问题:
trace
会把unittest
搞砸我不知道为什么
trace
不能正常工作,但是:
一个更简单的解决方法是将模块的名称显式传递给
unittest.main
:
import unittest
class Tester(unittest.TestCase):
def test_true(self):
self.assertTrue(True)
if __name__ == "__main__":
unittest.main(module='foobar')
trace
会在unittest
中搞乱测试发现,因为trace
是如何加载它正在运行的模块的<代码>跟踪读取模块源代码,编译它,并在\uuuuuu名称
全局设置为'\uuuuu main'
的上下文中执行它。这足以使大多数模块的行为看起来就像它们被调用为主模块一样,但实际上不会更改在Python解释器中注册为\uuuuu main\uuuuu
的模块。当unittest
要求\uuuuu main\uuuuu
模块扫描测试用例时,它实际上会从命令行调用跟踪
模块,该模块当然不包含单元测试
coverage.py
采取了不同的方法来实际替换sys.modules
中名为\uuu main\uuu
的模块,我喜欢Theran的答案,但至少在Python 3.6上有一些缺陷:
如果我运行了foobar.py
,但如果我运行了foobar.py Sometestclass
,只执行Sometestclass
,trace不会选择它并运行所有测试
我的解决方法是在适当的时候指定defaultTest:
请记住,unittest通常作为
python foobar.py
因此目标测试始终是最后一个参数,除非它是unittest选项,在这种情况下,它以-
开头。或者是foobar.py文件本身
lastarg = sys.argv[-1]
#not a flag, not foobar.py either...
if not lastarg.startswith("-") and not lastarg.endswith(".py"):
defaultTest = lastarg
else:
defaultTest = None
unittest.main(module=os.path.splitext(os.path.basename(__file__))[0], defaultTest=defaultTest)
无论如何,现在trace只执行所需的测试,或者如果我没有另外指定,则执行所有测试。我喜欢coverage.py,但我切换到trace.py,因为我需要它生成的*.cover文件(用于CDash执行的自动覆盖率分析)。有没有办法让coverage.py发出这些文件?我不知道.cover文件中有什么,但要从coverage.py收集的数据中生成它们并不难。请通过电子邮件联系我们,以便我们可以讨论。非常好的解释,谢谢。我只需要告诉测试模块它自己的(文件)名是什么,它本身和trace.py下都像一个符咒一样工作。顺便说一句:尝试将cProfile和unittest与
python-mcprofile[some_test_file.py]
一起使用时,会遇到同样的问题,解决方案也是一样的:unittest.main(module='tests')
。搜索引擎没有找到任何特定于cProfile的内容,所以添加了一条评论来帮助搜索。
lastarg = sys.argv[-1]
#not a flag, not foobar.py either...
if not lastarg.startswith("-") and not lastarg.endswith(".py"):
defaultTest = lastarg
else:
defaultTest = None
unittest.main(module=os.path.splitext(os.path.basename(__file__))[0], defaultTest=defaultTest)