cyau
cyau

Reputation: 449

Python unittest mock a function with optional default argument that may not be supplied

I'm trying to mock a function that looks like this [example]:

def f(overwrite=False):
    if overwrite:
        return "overwritten"
    else:
        return "skipping"

with a unittest.mock.Mock object that looks like this:

from unittest.mock import Mock, patch

mock_f = Mock(return_value = 'default', side_effect = lambda overwrite: 'overwrite' if overwrite else 'no overwrite')
#mock_f.func_defaults = (False,)
mock_f.__defaults__ = (False,)

mock_f()

The code above gives me an error (TypeError: <lambda>() missing 1 required positional argument: 'overwrite')

Since f itself can be called without supplying arguments, I need to be able to call mock_f() without arguments. However, if I try to call mock_f(True) or mock_f(False) it works fine. It doesn't work neither with mock_f.func_defaults nor with mock_f.__defaults__.

How should this be done?

Upvotes: 0

Views: 910

Answers (2)

progmatico
progmatico

Reputation: 4964

Use wraps to wrap fwith a mock but still execute the real methods:

from unittest.mock import patch

def f(overwrite=False):
    if overwrite:
        return "overwritten"
    else:
        return "skipping"


with patch('__main__.f', wraps=f) as mock_f:
    print(mock_f())
    print(mock_f(True))
    print(mock_f(False))

Output:

skipping
overwritten
skipping

Upvotes: 1

MrBean Bremen
MrBean Bremen

Reputation: 16805

The side_effect has to have the same signature as the function it replaces, if used this way (e.g. if assigned a function object). That means that you have to adapt the side_effect, not the mock:

>>> mock_f = Mock(return_value='default', side_effect=lambda
...               overwrite=False: 'overwrite' if overwrite else 'no overwrite')
>>> mock_f()

no overwrite

Upvotes: 2

Related Questions