Skip to content

Instantly share code, notes, and snippets.

@paul-butcher
Last active June 22, 2021 09:32
Show Gist options
  • Select an option

  • Save paul-butcher/a9c21ed662bc3f89db01f1ef514efb9c to your computer and use it in GitHub Desktop.

Select an option

Save paul-butcher/a9c21ed662bc3f89db01f1ef514efb9c to your computer and use it in GitHub Desktop.
Demonstration of using Mock.side_effect to return a different value on each call.
"""
Using Mock.side_effect with a list to provide multiple return values
"""
from unittest import mock
class MyClass:
@staticmethod
def hello(lang):
# Imagine that this function makes an unreliable, expensive, or slow network call
# to a translation service or something.
# You will want to mock it in unit tests to ensure that the function
# executes in reasonable time and without having to worry about network or credentials etc.
# In this case, it's a function that gives a greeting in the requested
# language. So you can imagine that it might check the current time and return
# a morning, afternoon, or evening greeting.
# Anything that returns a different result based on time of day needs to be mocked,
# otherwise tests that pass in the morning will fail in the evening.
if lang == 'deu':
return 'guten Tag'
if lang == 'nob':
return 'god dag'
@staticmethod
def greet():
return f'{MyClass.hello("deu")}, world! {MyClass.hello("nob")}, world!'
def bare_greet():
return f'{bare_hello("cym")}, world! {bare_hello("fra")}, world!'
def bare_hello(lang):
if lang == 'cym':
return 'bore da'
if lang == 'fra':
return 'bonjour'
def test_class_greet():
"""
You can patch out the method inside the test method,
giving an iterable to side_effect to cope with the fact that it is called
multiple times.
"""
with mock.patch.object(MyClass, 'hello') as mock_hello:
print('PATCHED: ')
mock_hello.side_effect = [
'guten abend', 'god kveld'
]
# You can assert, as normal, that the value returned by the function is what you expect,
# given the two values returned from the mock.
assert MyClass.greet() == 'guten abend, world! god kveld, world!'
# To be sure that the right arguments were provided in the right order,
# you can use assert_has_calls.
# This, in conjuction with asserting the value above, should give confidence that all is in order inside
# `greet` and that
assert mock_hello.call_count == 2
mock_hello.assert_has_calls([mock.call('deu'), mock.call('nob')])
def test_bare_greet():
with mock.patch('__main__.bare_hello') as mock_hello:
print('PATCHED: ')
mock_hello.side_effect = [
'noswaith dda', 'bonsoir'
]
assert bare_greet() == 'noswaith dda, world! bonsoir, world!'
assert mock_hello.call_count == 2
mock_hello.assert_has_calls([mock.call('cym'), mock.call('fra')])
if __name__ == '__main__':
print('NORMAL (Class): ')
MyClass.greet()
test_class_greet()
print('NORMAL (bare):')
bare_greet()
test_bare_greet()
print('DONE')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment