Skip to content Skip to sidebar Skip to footer

How To Make Pytest Wait For (manual) User Action?

We are sucessfully using pytest (Python 3) to run a test suite testing some hardware devices (electronics). For a subset of these tests, we need the tester to change the hardware

Solution 1:

So, I found a hint by a pytest dev, based on which I basically do what the capsys.disable() function does:

@pytest.fixture(scope="module")defdisconnect_component(pytestconfig):
    capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')

    capmanager.suspend_global_capture(in_=True)
    input('Disconnect component, then press enter')
    capmanager.resume_global_capture()

    yield# At this point all the tests with this fixture are run

    capmanager.suspend_global_capture(in_=True)
    input('Connect component again, then press enter')
    capmanager.resume_global_capture()

This works flawlessly as far as I can see. Don't forget the in_=True bit.

Edit: From pytest 3.3.0 (I think), capmanager.suspendcapture and capmanager.resumecapture were renamed to capmanager.suspend_global_capture and capmanager.resume_global_capture, respectively.

Solution 2:

As of pytest 5, as a fixture, you can use this:

@pytest.fixture
defsuspend_capture(pytestconfig):
    classsuspend_guard:def__init__(self):
            self.capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')
        def__enter__(self):
            self.capmanager.suspend_global_capture(in_=True)
        def__exit__(self, _1, _2, _3):
            self.capmanager.resume_global_capture()

    yield suspend_guard()

Example usage:

deftest_input(suspend_capture):
    with suspend_capture:
        input("hello")

Solution 3:

Maybe it's worth noting that above solution doesn't have to be in a fixture. I've made a helper function for that:

import pytest

defask_user_input(msg=''):
    """ Asks user to check something manually and answer a question
    """
    notification = "\n\n???\tANSWER NEEDED\t???\n\n{}".format(msg)

    # suspend input capture by py.test so user input can be recorded here
    capture_manager = pytest.config.pluginmanager.getplugin('capturemanager')
    capture_manager.suspendcapture(in_=True)

    answer = raw_input(notification)

    # resume capture after question have been asked
    capture_manager.resumecapture()

    logging.debug("Answer: {}".format(answer))
    return answer

Solution 4:

For future reference, if you need to use input with pytest. You can do this in any part of your pytest, setup_class, test_..., teardown_method, etc. This is for pytest > 3.3.x

import pytest

capture_manager = pytest.config.pluginmanager.getplugin('capturemanager')
capture_manager.suspend_global_capture(in_=True)
answer = input('My reference text here')
capture_manager.resume_global_capture()

Solution 5:

Solutions that use the global pytest.config object no longer work. For my use case, using --capture=sys together with a custom input() that uses stdin and stdout directly works well.

deffd_input(prompt):
    with os.fdopen(os.dup(1), "w") as stdout:
        stdout.write("\n{}? ".format(prompt))

    with os.fdopen(os.dup(2), "r") as stdin:
        return stdin.readline()

Post a Comment for "How To Make Pytest Wait For (manual) User Action?"