Explain Codes LogoExplain Codes Logo

Python mock multiple return values

python
mocking
unit-testing
test-coverage
Nikita BarsukovbyNikita Barsukov·Jan 27, 2025
TLDR

Get a quick win by creating a sequence of return values for a mock using unittest.mock's side_effect. Straightaway apply it to the mock's configuration:

from unittest.mock import MagicMock mock_func = MagicMock() # sequence: 'first', 'second', 'third' mock_func.side_effect = ['first', 'second', 'third'] # We choose the order of the universe! print(mock_func()) # Output: 'first' print(mock_func()) # Output: 'second' print(mock_func()) # Output: 'third'

Simply strap side_effect to an iterable armed with the desired return values. Each call to mock_func whisks away the next item.

Keep your gadgets handy for a more sophisticated response logic, deploy an iterator or a function as the side_effect. This enhances test versatility and mimics dynamic reaction scenarios more closely.

Harnessing iterators and iterables as side_effects

Spawn a Mock with an iterable

Commandeer a list or any iterable directly into side_effect to yield one value per call:

mock_obj = Mock() # Famous comic book dialogue sequence mock_obj.some_method.side_effect = ["I'm Batman!", "No, I'm Batman!", 'No, IM Batman...']

Now, mock_obj.some_method() will have an identity crisis—returns different Batman quotes at each call.

Dial up precision with an iterator

Collaborate with iter() alongside patch() to simulate user input via side_effect:

return_values = iter(['yes', 'no', 'maybe so']) with patch('module.func', side_effect=return_values) as mocked_func: # Sell seashells by the seashore, maybe? ...

The iterator state stands guard across calls, churning out the specified returns in tests.

Extensive test coverage for variable return values

Maneuver function calls without inputs

When the function doesn't bother about inputs, ensure uniform returns for each call:

mock_obj = Mock(return_value=None) # Mmm, pie flavor changes each time! mock_obj.method.side_effect = ['strawberry', 'blueberry', 'apple']

Ratify function calls and outputs

After donning the side_effect attire, concoct tests to validate:

  1. Function dials the right number of times.
  2. The output sequence plugs into the side_effect playlist.

Blasting exceptions using side_effects

To pull the pin on exceptions in a careful order along with valid return values:

mock_obj = Mock() # Walks like a duck, quacks like a duck, but... mock_obj.broken_method.side_effect = ['duck', 'duck', GooseError('GOOSE!')]

Remember if an exception blasts off, calls made post the explosion do not proceed unless caught mid-air within the test.

A spectrum of inputs, custom responses

When different inputs command different responses:

mock_obj = Mock() def side_effect(arg): # It's fruit salad day! returns = {'apple': 1, 'banana': 2, 'kiwi': 3} return returns.get(arg, 'Surprise!') mock_obj.method.side_effect = side_effect

The side_effect function here handles various tastes, mapping them to custom return values.

Dynamically altering the return flight

To mimic real-time maneuvers based on call history or external changes in course:

return_values = ['ascending', 'cruise', 'descend', 'landed'] def dynamic_side_effect(*args): # Like a paper airplane flight path. return return_values.pop(0) mock_obj.method.side_effect = dynamic_side_effect

This graphs the trajectory of a process over a period of time.

Conducting an orchestra of mock objects with side effects

Patching on instance methods

When photographing instance methods, aim right:

with patch.object(SomeClass, 'method', side_effect=[...]) as mock_method: # It's alive (Instance created)! instance = SomeClass() instance.method() # Sings the first aria ...

Amplifying class methods and static methods

Class and static methods must be patched backstage:

# These guys don't need an instance to sing. with patch.object(SomeClass, 'class_method', side_effect=[...]) as mock_class_method: ... with patch.object(SomeClass, 'static_method', side_effect=[...]) as mock_static_method: ...

Directing property symphonies with side_effect

Property values reflect their changing colors using side_effect as a PropertyMock:

with patch('module.Class.property', new_callable=PropertyMock) as mock_property: # Chameleons of class attributes. mock_property.side_effect = [val1, val2, val3] ...