unittest.py与trace.py配合不好 - 为什么?

Ron*_*ury 10 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()
Run Code Online (Sandbox Code Playgroud)

如果我运行它python foobar.py,我得到这个输出:

 .
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Run Code Online (Sandbox Code Playgroud)

大.现在我也想进行覆盖测试,所以我再次运行它python -m trace --count -C . foobar.py,但现在我得到了这个:

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK
Run Code Online (Sandbox Code Playgroud)

不,Python,它不行 - 你没有运行我的测试!似乎在trace某种程度上运行gums up 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)
Run Code Online (Sandbox Code Playgroud)

这基本上是一种解决方法,通过伪造它的副本来提升顶级模块的抽象,不可命名的名称.然后,我可以传递该名称,unittest.main()以便回避trace对它产生的任何影响.无需向您显示输出; 它看起来就像上面的成功例子.

所以,我有两个问题:

  1. 这里发生了什么?为什么trace搞砸了unittest

  2. 是否有一种更容易和/或更少疯狂的方法来解决这个问题?

The*_*ran 8

一个更简单的解决方法是将模块的名称显式传递给unittest.main:

import unittest

class Tester(unittest.TestCase):
    def test_true(self):
        self.assertTrue(True)

if __name__ == "__main__":
    unittest.main(module='foobar')
Run Code Online (Sandbox Code Playgroud)

traceunittest因为trace运行模块的加载方式而混淆了测试发现.trace读取模块源代码,编译它,并在__name__全局设置为的上下文中执行它'__main__'.这足以使大多数模块的行为就像它们被称为主模块一样,但实际上并没有改变__main__在Python解释器中注册的模块.当unittest要求__main__模块扫描测试用例时,它实际上trace从命令行获取调用的模块,当然这不包含单元测试.

coverage.py采用的实际替换该模块称为一种不同的方法__main__sys.modules.