Unit test performance#

Ideally we want to keep the run-time of the unit tests down so that they are quick for developers to run locally. Preferably they should run in under a minute.

General Guidelines#

Where a unit test waits for some event to happen, wait on the group to complete rather than adding a fixed sleep.

If testing a timeout, ensure that the timeout constant is either configurable or appropriately patch ed to a short value e.g. 0.1s

How to profile the unit tests#

Sometimes tests can exhibit slowdowns for unknown reasons, in order to diagnose the cause it can be useful to profile the test code.

The simplest way to find slow tests is to run pytest with the --durations option in order to find the slowest tests.

e.g.

pytest -m "not (s03 or dlstbx)" --durations=10

in order to find the top 10 slowest tests

You can then often step through in the debugger to find lines which execute slowly.

More detailed profiling#

Occasionally this is not sufficient. In which case more detailed profiling is necessary

Generating profiler output#

You can install pytest-profiling to run the tests and generate profiling output

e.g.

pip install pytest-profiling
pytest --profile tests/unit_tests/hyperion/external_interaction/test_write_rotation_nexus.py::test_given_detector_bit_depth_changes_then_vds_datatype_as_expected

The output of this is quite brief but it will generate more detailed .prof files in the prof directory

To browse these files you need something useful. Snakeviz is a tool that can be used to browse the output:

cd prof
pip install snakeviz
snakeviz combined.prof

An alternative tool is py-spy.

e.g.

pip install py-spy
py-spy record -o profile.svg -- pytest -s tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py::test_given_no_energy_supplied_when_robot_load_then_centre_current_energy_set_on_eiger

This will generator an interactive SVG flamechart that can be opened in a browser to see hot methods.

Alternatively something like

py-spy top -- pytest -s tests/unit_tests/hyperion/experiment_plans/test_robot_load_then_centre.py::test_given_no_energy_supplied_when_robot_load_then_centre_current_energy_set_on_eiger

to view a top -like updating view of where time is being spent. You will probably need to temporarily annotate the test with @pytest.mark.parametrize in order to make the tests loop sufficient times in order to observe.