Michael Johnson
Michael Johnson

Reputation: 470

Testing getpass module: 'password input may be echoed'

I'm looking for any insight into why the below error is raised. I'm wondering if the issue is with pytest?

I'm otherwise using getpass with no issues in my application. However, I'm new to the testing world.

common.py:

def username_password():
    """Get login credentials"""
    # show current windows user
    print("\nThe current windows user is {}\n".format(getuser()))

    username = getpass("Username: ")
    password = getpass("Password: ")
    return username, password

test_common.py:

from unittest.mock import patch
from common import username_password

@patch("getpass.getpass")
@patch("getpass.getuser")
def test_username_password(getuser, getpass):
    getuser.return_value = "Me"
    getpass.return_value = "xxx"
    assert username_password() == ("Me", "xxx")

Command line:

py.test test_common.py --cov  --cov-report term-missing
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: C:\Users\JB\Desktop\Coding\Bot\Bot_tests, inifile:
plugins: cov-2.5.1
collected 17 items

test_common.py ....F..x.........

================================== FAILURES ===================================
___________________________ test_username_password ____________________________

getuser = <MagicMock name='getuser' id='1759491735280'>
getpass = <MagicMock name='getpass' id='1759491732424'>

    @patch("getpass.getpass")
    @patch("getpass.getuser")
    def test_username_password(getuser, getpass):
        getuser.return_value = "Me"
        getpass.return_value = "xxx"
>       u, p = username_password()

test_common.py:65:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\Bot\common.py:29: in username_password
    username = getpass("Username: ")
..\..\environments\ipython_env\Anaconda3\lib\getpass.py:101: in win_getpass
    return fallback_getpass(prompt, stream)
..\..\environments\ipython_env\Anaconda3\lib\getpass.py:127: in fallback_getpass
    return _raw_input(prompt, stream)
..\..\environments\ipython_env\Anaconda3\lib\getpass.py:147: in _raw_input
    line = input.readline()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.capture.DontReadFromInput object at 0x00000199A8BD37F0>
args = ()

    def read(self, *args):
>       raise IOError("reading from stdin while output is captured")
E       OSError: reading from stdin while output is captured

..\..\environments\ipython_env\Anaconda3\lib\site-packages\_pytest\capture.py:433: OSError
---------------------------- Captured stdout call -----------------------------

The current windows user is JB

---------------------------- Captured stderr call -----------------------------
C:\Users\JB\Desktop\Coding\environments\ipython_env\Anaconda3\lib\getpass.py:101: GetPassWarning: Can not control echo on the terminal.
  return fallback_getpass(prompt, stream)
Warning: Password input may be echoed.
Username:
=============== 1 failed, 15 passed, 1 xfailed in 0.50 seconds ================

Any input appreciated.

Now babbling in the hope that the system will grant me the ability to post and stop asking for more details. I have nothing more to add.

Upvotes: 0

Views: 5338

Answers (2)

solly989
solly989

Reputation: 43

To work this I had to import getpass and use the method explicitly and then use a monkeypatch with an iterable.

common.py

import getpass

def username_password():
"""Get login credentials"""
    # show current windows user
    print("\nThe current windows user is {}\n".format(getuser()))

    username = getpass.getpass("Username: ")
    password = getpass.getpass("Password: ")
    return username, password

test_common.py

from common import username_password

def test_username_password(monkeypatch):
    responses = iter(['Me', 'xxx'])
    monkeypatch.setattr('getpass.getpass', lambda _: next(responses))    
    assert username_password() == ("Me", "xxx")

Upvotes: 3

phd
phd

Reputation: 94676

Fix: getpass -> input:

username = input("Username: ")

And patch input instead of getpass:

common.py:

def username_password():
    """Get login credentials"""
    # show current windows user
    print("\nThe current windows user is {}\n".format(getuser()))

    username = input("Username: ")
    password = getpass("Password: ")
    return username, password

test_common.py:

from unittest.mock import patch
from common import username_password

@patch("builtins.input")
@patch("getpass.getpass")
def test_username_password(input, getpass):
    input.return_value = "Me"
    getpass.return_value = "xxx"
    assert username_password() == ("Me", "xxx")

Upvotes: 1

Related Questions