How-to test an infinite loop
Let's say you have some code like this that you want to test:
There are several approaches if you want to (and can) modify the loop itself.
For example, we can add a flag, so that the actual loop depends on it. And that
flag can be set using some stop() method or by patching it during tests.
But if you really can't modify the loop, there is an option using signals:
import contextlib
import signal
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException
@contextlib.contextmanager
def timeout(timeout):
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(timeout)
with contextlib.suppress(TimeoutException):
yield
# Cancel signal if not yet triggered
signal.alarm(0)
You can use timeout in your tests like:
def test_runner(capsys):
with timeout(1):
runner()
captured = capsys.readouterr()
assert captured.out.startswith("Iterating")
But keep in mind that SIGALRM is only available in Unix systems.
If you want to include the test code in the coverage report generated by
coverage you'll need to add the
following setting to the config:
From the docs:
[run] sigterm (boolean, default False) if true, register a SIGTERM signal handler to capture data when the process ends due to a SIGTERM signal. This includes Process.terminate, and other ways to terminate a process. This can help when collecting data in usual situations, but can also introduce problems (see issue 1310).