Как узнать время, затраченное на каждый тест при использовании unittest?
Unittest отображает только общее время, затраченное на выполнение всех тестов, но не предоставляет информации о времени, затраченном на каждый отдельный тест.
Как можно добавить время выполнения каждого теста при использовании unittest?
5 ответ(ов)
Судя по всему, реализовать это на данный момент невозможно: https://github.com/python/cpython/issues/48330.
Тем не менее, вы можете сделать что-то подобное:
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
Таким образом, вы можете измерять время выполнения тестов, используя методы setUp
и tearDown
.
Вот вариант скрипта из ответа horejsek. Он будет изменять поведение Django TestCase так, что каждый тест будет выводить общее время выполнения.
Вы можете разместить этот скрипт в __init__.py
вашего корневого пакета, где находится settings.py
. После этого вы можете запускать тесты с помощью команды ./manage.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
Обратите внимание, что в данной реализации используется print
, чтобы вывести результат в консоль после завершения теста. Убедитесь, что вы используете Python 3, так как синтаксис print
изменился.
Решение только с использованием командной строки:
- Установите
nose
(популярный альтернативный тест-раннер) и расширениеpinocchio
:
$ pip install nose pinocchio
- Запустите тесты с записью времени (временные метрики будут сохранены в файл
.nose-stopwatch-times
):
$ nosetests --with-stopwatch
- Отобразите имена тестов, отсортированные по убыванию времени:
$ 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
Вы правы, использование time.perf_counter()
вместо time.time()
действительно может быть более точным для измерения времени выполнения. time.perf_counter()
предоставляет более высокую разрешающую способность и предназначен для измерения времени, что делает его более подходящим для этой задачи.
Ваши примеры отлично иллюстрируют это. Разница в измерениях действительно незначительна в данном случае, но в некоторых ситуациях, особенно в высокочувствительных приложениях, такая точность может иметь значение.
Более того, ваш декоратор для измерения времени выполнения функций выглядит очень полезным. Он позволяет легко отслеживать время выполнения различных функций и может стать хорошей практикой для тестирования производительности. Использование time.perf_counter()
внутри вашего декоратора также гарантирует, что вы будете получать наиболее точные результаты:
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
Наконец, если вы хотите использовать этот декорирующий метод в тестах, как вы сделали в вашем классе TestCase
, это может значительно упростить мониторинг производительности тестов. Это решение может быть полезно для всех, кто хочет улучшить точность своих измерений времени выполнения и следить за тем, как изменения в коде влияют на производительность.
unittest
теперь поддерживает измерение времени выполнения тестов на миллисекунды с помощью опции --durations 0
. Эта функция позволяет вам видеть, какие тесты выполняются дольше всего, и может помочь в оптимизации кода.
Вы можете запустить тесты с этой опцией следующим образом:
$ python -m unittest Lib.test.test_ftplib --durations 0
После выполнения команды вы увидите вывод, который включает список наиболее медленных тестов вместе с их временем выполнения. Например:
Slowest test durations
----------------------------------------------------------------------
0.000s test__all__ (Lib.test.test_ftplib.MiscTestCase)
0.002s test_pwd (Lib.test.test_ftplib.TestFTPClass)
...
1.281s test_mlsd (Lib.test.test_ftplib.TestTLS_FTPClassMixin)
В этом примере всего было выполнено 88 тестов за 5.396 секунд, и один из тестов был пропущен. Как видно, самый долгий тест занял 1.281 секунды, что может быть сигналом для оптимизации.
Самый быстрый способ проверить наличие значения в списке
Наиболее эффективный способ применения функции к массиву NumPy
Где размещать юнит-тесты на Python? [закрыто]
Python - объект MagicMock не может быть использован в выражении 'await'
Почему statistics.mean() работает так медленно?