18

I want to enforce that no test takes longer than 3 seconds in pytest.

pytest-timeout (https://pypi.python.org/pypi/pytest-timeout) almost does what I want... but it seems to allow me to either set a global timeout (ie make sure the test suite takes less than 10 minutes) or, an ability to set a decorator on each test manually.

Desired Behavior: Configure pytest with a single setting to fail any individual test which exceeds 3 seconds.

Marcel M
  • 1,244
  • 12
  • 19
user2917346
  • 321
  • 1
  • 4
  • 9

2 Answers2

5

From the pytest-timeout page:

You can set a global timeout in the py.test configuration file using the timeout option. E.g.:

[pytest]
timeout = 300
The Compiler
  • 11,126
  • 4
  • 40
  • 54
  • 7
    This answer is confusing, it makes no reference to the essential quandary of how to set a default *per-test* timeout. The docs actually now make this clear: "any individual test which takes longer than the given duration will be terminated" So whilst the answer is correct, it does not make clear why it's relevant to this particular form of the question. – tombh Jun 02 '22 at 20:57
5

You can use a local plugin. Place a conftest.py file into your project root or into your tests folder with something like the following to set the default timeout for each test to 3 seconds;

import pytest

def pytest_collection_modifyitems(items):
    for item in items:
        if item.get_marker('timeout') is None:
            item.add_marker(pytest.mark.timeout(3))

Pytest calls the pytest_collection_modifyitems function after it has collected the tests. This is used here to add the timeout marker to all of the tests.

Adding the marker only when it does not already exist (if item.get_marker...) ensures that you can still use the @pytest.mark.timeout decorator on those tests that need a different timeout.

Another possibility would be to assign to the special pytestmark variable somewhere at the top of a test module:

pytestmark = pytest.mark.timeout(3)

This has the disadvantage that you need to add it to each module, and in my tests I got an error message when I then attempted to use the @pytest.mark.timeout decorator anywhere in that module.

Marcel M
  • 1,244
  • 12
  • 19
  • Never heard of this, found really useful! – Samamba Dec 23 '21 at 16:08
  • I can't get this to work. A file containing the following happily executes forever. ```@pytest.mark.timeout(3) def test_timeout(): while True: x = 1 ``` My reading of your answer is that at a minimum that's all that's required and the "local plugin" and other stuff are for convenience. Can you clarify? – Iain Samuel McLean Elder Feb 01 '22 at 11:46
  • Have you installed pytest-timeout? To set a timeout for a single test, see https://stackoverflow.com/questions/19527320/ . This question/answer is about applying the timeout to all tests, for which using a local plugin is one option. – Marcel M Feb 01 '22 at 13:59