How to make pytest wait for a (manual) user action?

We successfully use pytest (Python 3) to run a test suite that tests some hardware devices (electronics). For a subset of these tests, we need a tester to change the hardware device and then change it. My approach was to use a modular device attached to the tests in question (they are all in a separate module), with two calls input:

@pytest.fixture(scope="module")
def disconnect_component():
    input('Disconnect component, then press enter')
    yield  # At this point all the tests with this fixture are run
    input('Connect component again, then press enter')

When doing this, I get OSError: reading from stdin while output is captured. I can avoid this by calling pytest with --capture=no, and confirmed that my approach works, that is, I get the first request before the subset in question, and the second after launch.

The big drawback is that it deactivates the stdin / stderr capture for the entire test suite that some other tests rely on.

I also tried using capsys.disabled( docs ) like this

@pytest.fixture(scope="module")
def disconnect_component(capsys):
    with capsys.disabled():
        input('Disconnect component, then press enter')
        yield  # At this point all the tests with this fixture are run
        input('Connect component again, then press enter')

but at startup I get ScopeMismatch: You tried to access the 'function' scoped fixture 'capsys' with a 'module' scoped request object, involved factories.

Can I make pytest wait for user action in some other way than input? If not, can I disable capture only for tests using the above device?

+5
source share
4 answers

So, I found a clue Developer Pytest, on which I am doing that capsys.disable()function capsys.disable():

@pytest.fixture(scope="module")
def disconnect_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()

, . in_=True.

: pytest 3.3.0 ( ), capmanager.suspendcapture capmanager.resumecapture capmanager.suspend_global_capture capmanager.resume_global_capture, .

+6

, , . :

import pytest

def ask_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
+2

, input pytest. pytest, setup_class, test_..., teardown_method .. 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()
+1

, pytest.config . --capture=sys input() stdin stdout .


def fd_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()
0

Source: https://habr.com/ru/post/1672141/


All Articles