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:Quoting the
Mock()
documentation:As an aside, the test
response is not 'y' or 'n' or 'yes' or 'no'
will not work; you are asking if the expression(response is not 'y')
is true, or'y'
is true (always the case, a non-empty string is always true), etc. The various expressions on either side ofor
operators are independent. See How do I test one variable against multiple values?You should also not use
is
to test against a string. The CPython interpreter may reuse string objects under certain circumstances, but this is not behaviour you should count on.As such, use:
instead; this will use equality tests (
==
) to determine ifresponse
references a string with the same contents (value).The same applies to
response == 'y' or 'yes'
; useresponse in ('y', 'yes')
instead.