4

I'm currently testing my python code and have a question about raw_input. This is my function:

def answer():
    ans = raw_input('enter yes or no')
    if ans == 'yes':
        print 'you entered yes'
        return 'yes'
    if ans == 'no':
        some_value = raw_input('enter some value: ')
        print 'you entered no'
        return some_value

I'm testing the first if statement this way:

with mock.patch('__builtin__.raw_input', return_value= 'yes'):
    assert answer() == 'yes'

But how do I check the no statement ? How do I make mock inside a mock ?

3 Answers 3

4

Using side_effect:

with mock.patch('__builtin__.raw_input', side_effect=['yes']):
    assert answer() == 'yes'
with mock.patch('__builtin__.raw_input', side_effect=['no', 'maybe']):
    assert answer() == 'maybe'

According to mock documentation:

If side_effect is an iterable then each call to the mock will return the next value from the iterable. The side_effect can also be any iterable object. Repeated calls to the mock will return values from the iterable (until the iterable is exhausted and a StopIteration is raised):

>>>
>>> m = MagicMock(side_effect=[1, 2, 3])
>>> m()
1
>>> m()
2
>>> m()
3
>>> m()
Traceback (most recent call last):
  ...
StopIteration
Sign up to request clarification or add additional context in comments.

Comments

2

Using side effect should do the trick, I find the following quite clear and avoid multiple with-block:

def my_side_effect(*args):  # each argument will be the return_value of one call
    for el in args:
        yield el  # we use a generator to return different value each time

with mock.patch('__builtin__.raw_input') as mocked:  # here the mocked object is accessible in the block
    mocked.side_effect = my_side_effect('yes')  # here one call that return 'yes'
    assert answer() == 'yes'
    mocked.side_effect = my_side_effect('no', 'maybe')  # two calls, the first return 'no', the second 'maybe'
    assert answer() == 'maybe'

1 Comment

I didn't realize side_effect could take a generator like this. Generators are always the easiest way to bundle up simple state. +1, only because I can't +10.
0

If you just mock raw_input to return 'no', it will return 'no' both times, meaning you can assert that the function returns 'no':

with mock.patch('__builtin__.raw_input', return_value='yes'):
    assert answer() == 'yes'
with mock.patch('__builtin__.raw_input', return_value='no'):
    assert answer() == 'no'

If you want to test what happens if, say, the first input is 'no' and the second one is 'maybe', you have to mock it with a function that returns different things the first time it's called and the second time it's called, and then you can assert that it returns 'maybe'. Something like this (not tested because I don't have mock installed here… but it should give you the idea):

def fake_raw_input(once=[False]):
    if not once[0]:
        once[0] = True
        return 'no'
    return 'maybe'

with mock.patch('__builtin__.raw_input', return_value='yes'):
    assert answer() == 'yes'
with mock.patch('__builtin__.raw_input', new_callable=fake_raw_input):
    assert answer() == 'maybe'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.