Подтвердить что ты не робот

Могу ли я запустить line_profiler над тестом pytest?

Я определил некоторые длительные тесты pytest с помощью

py.test --durations=10

Я хотел бы применить один из этих тестов к чему-то вроде line_profiler или cprofile. Я действительно хочу получить данные профиля из самого теста, так как установка pytest или срыв может быть частью медленного.

Однако, учитывая, как обычно задействуется line_profiler или cprofile, мне не ясно, как заставить их работать с pytest.

4b9b3361

Ответ 1

Запустить pytest следующим образом:

python -m cProfile -o profile $(which py.test)

Вы можете даже передать необязательные аргументы:

python -m cProfile -o profile $(which py.test) \
    tests/worker/test_tasks.py -s campaigns

Это создаст двоичный файл с именем profile в вашем текущем каталоге. Это можно проанализировать с помощью pstats:

import pstats
p = pstats.Stats('profile')
p.strip_dirs()
p.sort_stats('cumtime')
p.print_stats(50)

Это будет печатать 50 строк с самой длинной кумулятивной продолжительностью.

Ответ 2

Чтобы получить cProfile и line_profiler для работы с кодом py.test, я сделал две вещи:

  • Расширенный тестовый код py.test с вызовом pytest.main(), который сделал его исполняемым с интерпретатором python в качестве основного драйвера:

    # pytest_test.py:
    @profile # for line_profiler only
    def test_example():
        x = 3**32
        assert x == 1853020188851841
    
    # for profiling with cProfile and line_profiler
    import pytest
    pytest.main(__file__)
    

    Теперь вы можете запустить этот тест без py.test в качестве основного драйвера, используя другие инструменты:

    $ kernprof.py -l pytest_test.py
    $ python -m line_profiler pytest_test.py.lprof
    

    или

    $ python -m cProfile pytest_test.py
    
  • Чтобы профилировать специфичные для py.test функции, такие как pytest_funcarg*() с line_profiler, я разделил их на две части, чтобы избежать путаницы между py.test и line_profiler:

    def pytest_funcarg__foo(request):
        return foo(request)
    
    @profile
    def foo(request):
    ...
    

Тот же метод работает для memory_profiler.