【发布时间】:2012-02-29 16:05:54
【问题描述】:
Unittest 仅显示运行所有测试所花费的总时间,但不单独显示每个测试所花费的时间。
使用unittest时如何添加每个测试的计时?
【问题讨论】:
标签: python performance unit-testing
Unittest 仅显示运行所有测试所花费的总时间,但不单独显示每个测试所花费的时间。
使用unittest时如何添加每个测试的计时?
【问题讨论】:
标签: python performance unit-testing
我想,现在不可能:http://bugs.python.org/issue4080。
但是你可以这样做:
import unittest
import time
class SomeTest(unittest.TestCase):
def setUp(self):
self.startTime = time.time()
def tearDown(self):
t = time.time() - self.startTime
print('%s: %.3f' % (self.id(), t))
def testOne(self):
time.sleep(1)
self.assertEqual(int('42'), 42)
def testTwo(self):
time.sleep(2)
self.assertEqual(str(42), '42')
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(SomeTest)
unittest.TextTestRunner(verbosity=0).run(suite)
结果:
__main__.SomeTest.testOne: 1.001
__main__.SomeTest.testTwo: 2.002
----------------------------------------------------------------------
Ran 2 tests in 3.003s
OK
【讨论】:
您可以将pytest 与--durations=0 一起使用,它会为您提供每次测试的执行时间
【讨论】:
Nose 使用 pinnochio extension 进行测试有一个 stopwatch 选项,如果你可以选择鼻子,它会给你这个。
它还有很多其他有用的功能和插件可以让使用 unittest 更好。
【讨论】:
这里是 horejsek 回答的脚本变体。 它将猴子补丁 django TestCase 以便每个 TestCase 都会给出它的总运行时间。
您可以将此 sript 放置在您的 settings.py 所在的根包的 __init__.py 中。 之后,您可以使用 ./mange.py test -s
运行测试from django import test
import time
@classmethod
def setUpClass(cls):
cls.startTime = time.time()
@classmethod
def tearDownClass(cls):
print "\n%s.%s: %.3f" % (cls.__module__, cls.__name__, time.time() - cls.startTime)
test.TestCase.setUpClass = setUpClass
test.TestCase.tearDownClass = tearDownClass
【讨论】:
仅使用命令行的解决方案:
1/ 安装nose(流行的替代测试运行器)和扩展pinocchio
$ pip install nose pinocchio
2/ 运行测试并记录时间(时间保存在文件.nose-stopwatch-times中)
$ nosetests --with-stopwatch
3/ 显示按时间递减排序的测试名称:
$ python -c "import pickle,operator,signal; signal.signal(signal.SIGPIPE, signal.SIG_DFL); print '\n'.join(['%.03fs: %s'%(v[1],v[0]) for v in sorted(pickle.load(open('.nose-stopwatch-times','r')).items(), key=operator.itemgetter(1), reverse=True)])" | less
【讨论】:
s时打印ms
pinnochio 错字:应该是pinocchio
您可以使用django-slowtests,它提供如下输出:
$ python manage.py test
Creating test database for alias 'default'...
..........
----------------------------------------------------------------------
Ran 10 tests in 0.413s
OK
Destroying test database for alias 'default'...
Ten slowest tests:
0.3597s test_detail_view_with_a_future_poll (polls.tests.PollIndexDetailTests)
0.0284s test_detail_view_with_a_past_poll (polls.tests.PollIndexDetailTests)
0.0068s test_index_view_with_a_future_poll (polls.tests.PollViewTests)
0.0047s test_index_view_with_a_past_poll (polls.tests.PollViewTests)
0.0045s test_index_view_with_two_past_polls (polls.tests.PollViewTests)
0.0041s test_index_view_with_future_poll_and_past_poll (polls.tests.PollViewTests)
0.0036s test_index_view_with_no_polls (polls.tests.PollViewTests)
0.0003s test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
0.0002s test_was_published_recently_with_recent_poll (polls.tests.PollMethodTests)
0.0002s test_was_published_recently_with_old_poll (polls.tests.PollMethodTests)
如果您查看django_slowtests/test_runner.py,您也可以自己调整该技术。
【讨论】:
PyCharm CE (free) 提供了unittest 持续时间的清晰视图。它还有助于按目录结构和文件进行聚合,并允许您按持续时间排序:
正如@horejsek 所提到的,unittest 在使用开放 PR 添加持续时间测量时存在问题:https://github.com/python/cpython/pull/12271。
【讨论】:
我订阅了所有其他用户的答案,但他们大多有一个小问题。
其实用time.perf_counter()代替time.time()更准确
def perf_time():
start = time.perf_counter()
time.sleep(1)
end = time.perf_counter()
print(end - start)
def time_time():
start = time.time()
time.sleep(1)
end = time.time()
print(end - start)
>>> time_time()
1.0010485649108887
>>> perf_time()
1.0010385409987066
这里的差异很小,但有时这真的很重要。
我也可以为这个主题分享一个不错的装饰器:
def time_func(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__}: {end - start:.3}s")
return result
return wrapper
class TestCase(unittest.TestCase):
@time_func
def test_case(self):
【讨论】: