【问题标题】:Why cProfile module doesn't work with unittest?为什么 cProfile 模块不适用于 unittest?
【发布时间】:2012-07-23 14:56:01
【问题描述】:

我会使用 cProfile 模块来分析我的单元测试。但是当我跑步时

python -mcProfile mytest.py

我得到了“在 0.000 秒内运行 0 次测试”。这是mytest.py的源代码

import unittest

class TestBasic(unittest.TestCase):
    def testFoo(self):
        assert True == True

if __name__ == '__main__':
    unittest.main()

我也用其他更复杂的单元测试进行了测试。如果我使用 cProfile 运行它,总是得到“运行 0 次测试”。请帮忙。

更新:我的操作系统是 MacOS 10.7,内置 python 2.7。相同的代码在 ubuntu 上也能正常运行。

【问题讨论】:

  • 在 Ubuntu - python2.6/2.7 下为我工作 :) 你尝试过仅使用 Profile 模块吗?
  • 谢谢,朱利安。刚刚在ubuntu上测试过,它可以工作。看起来它是一个特定于平台的问题。它不适用于内置 python 2.7 的 MacOS 10.7。
  • 我猜你从来没有找到让它在 Mac OS X 上运行的方法?
  • 我意识到这个问题有点老了,但它似乎并不特定于 OS X:我可以用 Ubuntu 13.04 和 Python 2.7.4 重现问题中的问题。不幸的是,我也没有答案。

标签: python macos unit-testing cprofile


【解决方案1】:

您必须在测试的构造函数中初始化 cProfiler,并在析构函数中使用配置文件数据——我是这样使用的:

from pstats import Stats
import unittest

class TestSplayTree(unittest.TestCase):
    """a simple test"""

    def setUp(self):
        """init each test"""
        self.testtree = SplayTree (1000000)
        self.pr = cProfile.Profile()
        self.pr.enable()
        print "\n<<<---"

    def tearDown(self):
        """finish any test"""
        p = Stats (self.pr)
        p.strip_dirs()
        p.sort_stats ('cumtime')
        p.print_stats ()
        print "\n--->>>"

    def xtest1 (self):
        pass

如果测试等待输入,则需要在调用之前调用self.pr.disable(),然后重新启用它。

如果您更喜欢pytest,方法名称会有所不同:

import cProfile
import time

class TestProfile:
    """ test to illustrate cProfile usage """

    def setup_class(self):
        self.pr = cProfile.Profile()
        self.pr.enable()

    def teardown_class(self):
        self.pr.disable()
        self.pr.print_stats(sort="tottime")

    def test_sleep(self):
        time.sleep(2)

【讨论】:

  • 当我想使用烧瓶测试客户端时仍然不适合我。
  • 仅供参考,Stats 课程可通过from pstats import Stats获得
  • self.testtree = SplayTree (1000000) 在这里必不可少吗?
  • 我从我的伸展树实现中复制并粘贴,非常古老。我想我是在大约 3 年前做的。无论如何,我的实现效果很好。如果你真的需要,我可以打开档案看看。
  • 不需要self.testtree = SplayTree (1000000)。或者您需要为其提供导入
【解决方案2】:

我不知道为什么,但显式创建和运行测试套件似乎可行。我添加了time.sleep(2) 以在统计数据中显示一些明确的信息。

import time
import unittest

class TestBasic(unittest.TestCase):
    def testFoo(self):
        time.sleep(2)
        assert True == True

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestBasic)
    unittest.TextTestRunner(verbosity=2).run(suite)

在 bash 中运行,只保留前 10 行,我们可以看到 {time.sleep} 是运行时间最长的调用:

~ $ python -m cProfile -s tottime so.py | head -n10
testFoo (__main__.TestBasic) ... ok

----------------------------------------------------------------------
Ran 1 test in 2.003s

OK
         1084 function calls (1072 primitive calls) in 2.015 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.003    2.003    2.003    2.003 {time.sleep}
        1    0.002    0.002    0.003    0.003 case.py:1(<module>)
        1    0.002    0.002    0.003    0.003 collections.py:11(<module>)
        1    0.001    0.001    2.015    2.015 so.py:1(<module>)
        1    0.001    0.001    0.010    0.010 __init__.py:45(<module>)

【讨论】:

    【解决方案3】:

    指定模块明确地为我解决了这个问题。也就是替换……

        unittest.main()
    

    ...(它试图自动发现它应该运行哪些测试)...

        unittest.main(module='mytest')  # if in 'mytest.py', or as appropriate for your filename/module
    

    ...允许以python -m cProfile mytest.py 进行正确的分析。

    【讨论】:

    • 正如对这个想法的解释:默认情况下,unittest.main() 在 'main' 模块中查找单元 TestCase 对象。因此,当我们通过 cProfile 运行它时,模块名称不同,并且当我们在 unittest.main(module='mytest') 中定义显式名称时,它可以工作
    • 有效,并且是迄今为止最不干扰和最复杂的答案。
    猜你喜欢
    • 2020-12-16
    • 2018-06-19
    • 2019-09-30
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 2021-02-22
    • 2016-11-20
    • 1970-01-01
    相关资源
    最近更新 更多