Skip to content

Commit 411ef56

Browse files
committed
Use context managers and decorators for mocks
Mocks of six.moves.input() and sys.stdin.isatty() now use either a context manager or a decorator. These wrappers make sure to put the functions back to their unmocked values when the test is done. This change appears to have solved the undeterministic test results.
1 parent 503ea98 commit 411ef56

File tree

1 file changed

+27
-33
lines changed

1 file changed

+27
-33
lines changed

tests/test_cmd2.py

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,37 +1390,37 @@ def test_echo(capsys):
13901390
assert out.startswith('{}{}\n'.format(app.prompt, command) + 'history [arg]: lists past commands issued')
13911391

13921392
def test_pseudo_raw_input_tty_rawinput_true():
1393-
minput = mock.MagicMock(name='input', side_effect=['set', 'quit'])
1394-
sm.input = minput
1395-
mtty = mock.MagicMock(name='isatty', return_value=True)
1396-
sys.stdin.isatty = mtty
1397-
1398-
# run the cmdloop, which should pull input from the mocked input
1399-
app = cmd2.Cmd()
1400-
app.use_rawinput = True
1401-
app._cmdloop()
1393+
# use context managers so original functions get put back when we are done
1394+
# we dont use decorators because we need m_input for the assertion
1395+
with mock.patch('sys.stdin.isatty',
1396+
mock.MagicMock(name='isatty', return_value=True)):
1397+
with mock.patch('six.moves.input',
1398+
mock.MagicMock(name='input', side_effect=['set', 'quit'])) as m_input:
1399+
# run the cmdloop, which should pull input from our mocks
1400+
app = cmd2.Cmd()
1401+
app.use_rawinput = True
1402+
app._cmdloop()
1403+
# because we mocked the input() call, we won't get the prompt
1404+
# or the name of the command in the output, so we can't check
1405+
# if its there. We assume that if input got called twice, once
1406+
# for the 'set' command, and once for the 'quit' command,
1407+
# that the rest of it worked
1408+
assert m_input.call_count == 2
14021409

1403-
# because we mocked the input() call, we won't see the prompt
1404-
# or the name of the command in the output, so we can't check
1405-
# if its there. We assume that if input got called twice, once
1406-
# for the 'set' command, and once for the 'quit' command,
1407-
# that the rest of it worked
1408-
assert minput.call_count == 2
1409-
14101410
def test_pseudo_raw_input_tty_rawinput_false():
1411-
# mock up the input
1411+
# gin up some input like it's coming from a tty
14121412
fakein = io.StringIO(u'{}'.format('set\nquit\n'))
14131413
mtty = mock.MagicMock(name='isatty', return_value=True)
14141414
fakein.isatty = mtty
14151415
mreadline = mock.MagicMock(name='readline', wraps=fakein.readline)
14161416
fakein.readline = mreadline
1417-
1417+
14181418
# run the cmdloop, telling it where to get input from
14191419
app = cmd2.Cmd(stdin=fakein)
14201420
app.use_rawinput = False
14211421
app._cmdloop()
14221422

1423-
# because we mocked the readline() call, we won't see the prompt
1423+
# because we mocked the readline() call, we won't get the prompt
14241424
# or the name of the command in the output, so we can't check
14251425
# if its there. We assume that if readline() got called twice, once
14261426
# for the 'set' command, and once for the 'quit' command,
@@ -1429,29 +1429,28 @@ def test_pseudo_raw_input_tty_rawinput_false():
14291429

14301430
# the next helper function and two tests check for piped
14311431
# input when use_rawinput is True.
1432-
#
1433-
# the only way to make this testable is to mock the builtin input()
1434-
# function
14351432
def piped_rawinput_true(capsys, echo, command):
1436-
m = mock.Mock(name='input', side_effect=[command, 'quit'])
1437-
sm.input = m
1438-
1439-
# run the cmdloop, which should pull input from our mocked input
14401433
app = cmd2.Cmd()
14411434
app.use_rawinput = True
14421435
app.echo = echo
1443-
app.abbrev = False
1436+
# run the cmdloop, which should pull input from our mock
14441437
app._cmdloop()
14451438
out, err = capsys.readouterr()
14461439
return (app, out)
14471440

1441+
# using the decorator puts the original function at six.moves.input
1442+
# back when this method returns
1443+
@mock.patch('six.moves.input', mock.MagicMock(name='input', side_effect=['set', 'quit']))
14481444
def test_pseudo_raw_input_piped_rawinput_true_echo_true(capsys):
14491445
command = 'set'
14501446
app, out = piped_rawinput_true(capsys, True, command)
14511447
out = out.splitlines()
14521448
assert out[0] == '{}{}'.format(app.prompt, command)
14531449
assert out[1] == 'abbrev: False'
14541450

1451+
# using the decorator puts the original function at six.moves.input
1452+
# back when this method returns
1453+
@mock.patch('six.moves.input', mock.MagicMock(name='input', side_effect=['set', 'quit']))
14551454
def test_pseudo_raw_input_piped_rawinput_true_echo_false(capsys):
14561455
command = 'set'
14571456
app, out = piped_rawinput_true(capsys, False, command)
@@ -1460,14 +1459,9 @@ def test_pseudo_raw_input_piped_rawinput_true_echo_false(capsys):
14601459
assert not '{}{}'.format(app.prompt, command) in out
14611460

14621461
# the next helper function and two tests check for piped
1463-
# input when use_rawinput is False
1464-
#
1465-
# the only way to make this testable is to pass a file handle
1466-
# as stdin
1462+
# input when use_rawinput=False
14671463
def piped_rawinput_false(capsys, echo, command):
1468-
# mock up the input
14691464
fakein = io.StringIO(u'{}'.format(command))
1470-
14711465
# run the cmdloop, telling it where to get input from
14721466
app = cmd2.Cmd(stdin=fakein)
14731467
app.use_rawinput = False

0 commit comments

Comments
 (0)