Search code examples
pythonpytest

Run slow Pytest commands at the end of the test suite


Let's say I have the following pytest script:

import pytest

def test_one():
    pass

def test_two():
    pass

@pytest.mark.slow
def test_three():
    pass

Is there a single command I can use to run all tests with the slow marker last? I know I can do this using two pytest commands but it would be great to do this using a single command:

pytest -v -m "not slow"
# test_markers.py::test_one PASSED                                                                                                                    
# test_markers.py::test_two PASSED

pytest -v -m slow
# test_markers.py::test_three PASSED

Solution

  • You can add custom sorting of collected tests and place the items with the slow marker last. Put the following code in a file conftest.py in your project or test root dir:

    from _pytest.mark import Mark
    
    
    empty_mark = Mark('', [], {})
    
    
    def by_slow_marker(item):
        return item.get_closest_marker('slow', default=empty_mark)
    
    
    def pytest_collection_modifyitems(items):
        items.sort(key=by_slow_marker, reverse=False)
    

    This will place the items having the slow marker at the end of the collected tests sequence. If you want to turn this functionality on and off, add a custom command line flag:

    def pytest_addoption(parser):
        parser.addoption('--slow-last', action='store_true', default=False)
    
    
    def pytest_collection_modifyitems(items, config):
        if config.getoption('--slow-last'):
            items.sort(key=by_slow_marker, reverse=True)
    

    Running pytest --slow-last will now resort the items.