В дискорде Django вопрос:
Как вы выполняете 2105 тестов менее чем за 2 минуты? В моем проекте набор из 75 тестов выполняется 30 секунд.
По идее запуск миллиона пустых тестов должен быть довольно быстрым, ведь дело не в количестве тестов, а в том, что эти тесты делают.
Создал файл с миллионом пустых тестов:
with open('tests.py', 'w') as f: for i in range(1_000_000): f.write(f'def test_{i}():\n pass\n')
И запустил с помощью pytest, результат:
5 минут
Это много. Может, дело в задержке на печать? -q не удаляет вывод каждого теста, а команда:
pytest tests.py -q --assert=plain 2>&1 >/dev/null
— не влияет на время выполнения.
Попробовал выполнить этот файл в кастомном тест-раннере hammett:
22 секунды
Уже лучше. Интересно, а минимальное теоретическое время? Потому что hammett загружает файл, просматривает его, чтобы найти все функции, выполняет их все, собирает результаты, и печатает точку в терминале для каждого теста.
Я подумал, что абсолютным теоретически минимальным вариантом будет просто выполнить:
python tests.py
Время получилось:
8,4 секунды
Много. Но в Hammett есть 100% тихий режим -q, который несомненно должен быть быстрее обычного:
12.9 секунды
Понятно.
Теперь я повторно запускаю pytest, чтобы посмотреть что происходит, и замечаю, что:
4,25 гиг RAM
Это очень много. А если через Hammett?
1,07 гига RAM
Вот так. Теперь
python tests.py
теперь
2,7 гига RAM
А если:
python -m tests.py
1,1 секунды
и
~500 Мб RAM
Разница между python -m tests и python tests.py изумительна.
ConfusedReptile в Python Discord сообщил, что дело в кэшировании байткода, вот это я забыл.
Удаление __pycache__ и запуск python -m tests делает выполнение таким же медленным как python tests.py.
Вернувшись с этим знанием, я сначала удаляю __pycache__, и hammett теперь выполняется 12-20 секунд, как и следовало ожидать.
Урок заключается в том, что парсинг исходного Python-файла в целом определяет время выполнения теста.