Why cProfile module doesn't work with unittest?
You have to initialize the cProfiler in the Constructor of the test, and use the profile data in destructor -- I use it like that:
from pstats import Statsimport unittestclass 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
In case that a test waits for input, one needs to call self.pr.disable()
before that call, and re-enable it afterwards.
If you prefer pytest
the method names are a bit different:
import cProfileimport timeclass 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)
Specifying the module explicitly fixed this for me. That is, replacing...
unittest.main()
...(which tried to auto-discover what tests it should be running) with...
unittest.main(module='mytest') # if in 'mytest.py', or as appropriate for your filename/module
...allowed proper profiling as python -m cProfile mytest.py
.
I'm not sure why, but explicitly creating and running a test suite seems to work. I added time.sleep(2)
to show something definitive in the stats.
import timeimport unittestclass TestBasic(unittest.TestCase): def testFoo(self): time.sleep(2) assert True == Trueif __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(TestBasic) unittest.TextTestRunner(verbosity=2).run(suite)
Running in bash, only keeping the first 10 lines, we can see {time.sleep}
was the longest running call:
~ $ python -m cProfile -s tottime so.py | head -n10testFoo (__main__.TestBasic) ... ok----------------------------------------------------------------------Ran 1 test in 2.003sOK 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>)