3

I am trying to simulate user input for a python script that I have going using py.test. Here's some basic code that represents what I'm trying to accomplish:

def ask():
    while True:
        age = input("Enter your age: ")
        if int(age) < 13:
            print("You are too young")
        else:
            name = input("Enter your name: ")
            break
    print("Welcome!")

I would like to mimic user input and read the output. An example might be something like:

@mock.patch('builtins.input', side_effect=['11'])
def test_invalid_age():
    ask()
    assert stdout == "You are too young"

I've also heard that flexmock might be a better alternative to the built-in unittest mocking system, but I'll take any solution at this point.

Update:

I played around a bit more and have a test that is this:

@mock.patch('builtins.input', side_effect=['11'])
def test_bad_params(self, input):
    ask()
    output = sys.stdout.getline().strip()
    assert output == "You are too young"

When I run py.test I get this result:

E StopIteration /usr/lib/python3.3/unittest/mock.py:904:
StopIteration

It did catch capture the appropriate standard output call as "You are too young".

nbb
  • 295
  • 3
  • 10
  • What exactly is your question? Have you tried to implement this? Did you run the example? What happened? Have a look at e.g. http://stackoverflow.com/q/2617057/3001761 – jonrsharpe May 04 '15 at 20:39

1 Answers1

6

ask doesn't return after the first too-young age; it loops until an appropriate age is entered. As written, you'll need to supply all the strings it might read, then do all your assertions after ask returns.

@mock.patch('builtins.input', side_effect=['11', '13', 'Bob'])
def test_bad_params(self, input):
    ask()
    output = sys.stdout.getline().strip()
    assert output == "You are too young"
    # Check the output after "13" and "Bob" are entered as well!
    assert sys.stdout.getline().strip() == "Welcome!"
chepner
  • 497,756
  • 71
  • 530
  • 681