waitSignal: Waiting for threads, processes, etc.

New in version 1.2.

If your program has long running computations running in other threads or processes, you can use qtbot.waitSignal to block a test until a signal is emitted (such as QThread.finished) or a timeout is reached. This makes it easy to write tests that wait until a computation running in another thread or process is completed before ensuring the results are correct:

def test_long_computation(qtbot):
    app = Application()

    # Watch for the app.worker.finished signal, then start the worker.
    with qtbot.waitSignal(app.worker.finished, timeout=10000) as blocker:
        blocker.connect(app.worker.failed)  # Can add other signals to blocker
        app.worker.start()
        # Test will block at this point until either finished or failed
        # signals is emitted or 10 seconds has elapsed

    assert blocker.signal_triggered, "process timed-out"
    assert_application_results(app)

raising parameter

New in version 1.4.

You can pass raising=True to raise a qtbot.SignalTimeoutError if the timeout is reached before the signal is triggered:

def test_long_computation(qtbot):
    ...
    with qtbot.waitSignal(app.worker.finished, raising=True) as blocker:
        app.worker.start()
    # if timeout is reached, qtbot.SignalTimeoutError will be raised at this point
    assert_application_results(app)

Note

The default value for raising is planned to change to True starting in pytest-qt version 1.12. Users wishing to preserve the current behavior (raising is False by default) should make use of the new qt_wait_signal_raising ini option.

qt_wait_signal_raising ini option

New in version 1.11.

The qt_wait_signal_raising ini option can be used to override the default value of the raising parameter of the qtbot.waitSignal and qtbot.waitSignals functions when omitted:

[pytest]
qt_wait_signal_raising = true

Calls which explicitly pass the raising parameter are not affected.

Getting arguments of the emitted signal

New in version 1.10.

The arguments emitted with the signal are available as the args attribute of the blocker:

def test_signal(qtbot):
    ...
    with qtbot.waitSignal(app.got_cmd) as blocker:
        app.listen()
    assert blocker.args == ['test']

Signals without arguments will set args to an empty list. If the time out is reached instead, args will be None.

waitSignals

New in version 1.4.

If you have to wait until all signals in a list are triggered, use qtbot.waitSignals, which receives a list of signals instead of a single signal. As with qtbot.waitSignal, it also supports the raising parameter:

def test_workers(qtbot):
    workers = spawn_workers()
    with qtbot.waitSignal([w.finished for w in workers], raising=True):
        for w in workers:
            w.start()

    # this will be reached after all workers emit their "finished"
    # signal or a qtbot.SignalTimeoutError will be raised
    assert_application_results(app)

Making sure a given signal is not emitted

New in version 1.11.

If you want to ensure a signal is not emitted in a given block of code, use the qtbot.assertNotEmitted context manager:

def test_no_error(qtbot):
    ...
    with qtbot.assertNotEmitted(app.worker.error):
        app.worker.start()