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

匿名 (未验证) 提交于 2019-12-03 03:03:02

问题:

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 arrangement, and afterwards change it back. My approach was to use a module-level fixture attached to the tests in question (which are all in a separate module), with two input calls:

@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 running this, I get OSError: reading from stdin while output is captured. I can avoid this by calling pytest with --capture=no, and have confirmed that my approach works, meaning I get the first query before the test subset in question, and the second one after they have run.

The big drawback is that this deactivates capturing stdin/stderr for the whole test suite, which some of the other test rely on.

I also tried to use 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 when running this 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 capturing just for the tests using above fixture?

回答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") def disconnect_component(pytestconfig):     capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')      capmanager.suspendcapture(in_=True)     input('Disconnect component, then press enter')     capmanager.resumecapture()      yield  # At this point all the tests with this fixture are run      capmanager.suspendcapture(in_=True)     input('Connect component again, then press enter')     capmanager.resumecapture() 

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



回答2:

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  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 


回答3:

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() 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!