Python mock multiple return values
Question:
I am using pythons mock.patch and would like to change the return value for each call.
Here is the caveat:
the function being patched has no inputs, so I can not change the return value based on the input.
Here is my code for reference.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
My Test code:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
is just a platform independent (python 2 and 3) version of “input”. So ultimately I am trying to mock out the users input. I have tried using a list for the return value, but that doesn’t seam to work.
You can see that if the return value is something invalid, I will just get an infinite loop here. So I need a way to eventually change the return value, so that my test actually finishes.
(another possible way to answer this question could be to explain how I could mimic user input in a unit-test)
Not a dup of this question mainly because I do not have the ability to vary the inputs.
One of the comments of the Answer on this question is along the same lines, but no answer/comment has been provided.
Answers:
You can assign an iterable to side_effect
, and the mock will return the next value in the sequence each time it is called:
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'
Quoting the Mock()
documentation:
If side_effect is an iterable then each call to the mock will return the next value from the iterable.
You can also use patch for multiple return values:
@patch('Function_to_be_patched', return_value=['a', 'b', 'c'])
Remember that if you are making use of more than one patch for a method then the order of it will look like this:
@patch('a')
@patch('b')
def test(mock_b, mock_a);
pass
as you can see here, it will be reverted. First mentioned patch will be in the last position.
for multiple return values, we can use side_effect during patch initializing also and pass iterable to it
sample.py
def hello_world():
pass
test_sample.py
from unittest.mock import patch
from sample import hello_world
@patch('sample.hello_world', side_effect=[{'a': 1, 'b': 2}, {'a': 4, 'b': 5}])
def test_first_test(self, hello_world_patched):
assert hello_world() == {'a': 1, 'b': 2}
assert hello_world() == {'a': 4, 'b': 5}
assert hello_world_patched.call_count == 2
I think the simplest solution is using a combination of iter()
, patch()
, side_effect
.
from unittest.mock import patch
from return_inputs import *
def test_something_that_has_2_inputs(self):
input_list = ['Foo', 'Bar']
inputs = iter(input_list)
with patch("builtins.input", side_effect=inputs):
name1, name2 = return_inputs()
assert name1 == "Foo"
assert name2 == 'Bar'
I am using pythons mock.patch and would like to change the return value for each call.
Here is the caveat:
the function being patched has no inputs, so I can not change the return value based on the input.
Here is my code for reference.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
My Test code:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
is just a platform independent (python 2 and 3) version of “input”. So ultimately I am trying to mock out the users input. I have tried using a list for the return value, but that doesn’t seam to work.
You can see that if the return value is something invalid, I will just get an infinite loop here. So I need a way to eventually change the return value, so that my test actually finishes.
(another possible way to answer this question could be to explain how I could mimic user input in a unit-test)
Not a dup of this question mainly because I do not have the ability to vary the inputs.
One of the comments of the Answer on this question is along the same lines, but no answer/comment has been provided.
You can assign an iterable to side_effect
, and the mock will return the next value in the sequence each time it is called:
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'
Quoting the Mock()
documentation:
If side_effect is an iterable then each call to the mock will return the next value from the iterable.
You can also use patch for multiple return values:
@patch('Function_to_be_patched', return_value=['a', 'b', 'c'])
Remember that if you are making use of more than one patch for a method then the order of it will look like this:
@patch('a')
@patch('b')
def test(mock_b, mock_a);
pass
as you can see here, it will be reverted. First mentioned patch will be in the last position.
for multiple return values, we can use side_effect during patch initializing also and pass iterable to it
sample.py
def hello_world():
pass
test_sample.py
from unittest.mock import patch
from sample import hello_world
@patch('sample.hello_world', side_effect=[{'a': 1, 'b': 2}, {'a': 4, 'b': 5}])
def test_first_test(self, hello_world_patched):
assert hello_world() == {'a': 1, 'b': 2}
assert hello_world() == {'a': 4, 'b': 5}
assert hello_world_patched.call_count == 2
I think the simplest solution is using a combination of iter()
, patch()
, side_effect
.
from unittest.mock import patch
from return_inputs import *
def test_something_that_has_2_inputs(self):
input_list = ['Foo', 'Bar']
inputs = iter(input_list)
with patch("builtins.input", side_effect=inputs):
name1, name2 = return_inputs()
assert name1 == "Foo"
assert name2 == 'Bar'