Consider a module with a 'public' function which looks something like this:
def func(arg):
val = _generate_something(arg)
_do_something(val)
As you can see this is a 'void function'. Its core logic is in _generate_something
.
I want to write unit tests for this function. I can think of several approaches to do so. I would like to know what the best one is, both in terms of general programming practices and best practice in Python specifically.
Essentialy this question is about the Pythonic way of mocking a private function (money patching? Injecting the function? Injecting an object? Etc.)
Option A
In the test monkeypatch _do_something
(which is a 'private' function of the module), so I can check it receives a good value.
Option B
Inject _do_something
as an argument to func
, like so:
def func(arg, do_something=None):
do_something = do_something or _do_something # in production use default
val = _generate_something(arg)
do_something(val)
Then in my do_something
mock I can check I received the correct value.
Option C
Have func
be a method of a class, and have that class take do_something
as an argument to __init__
:
class Something(object):
def __init__(self, do_something=None):
self._do_something = do_something or _production_default
def func(self, arg):
val = self._generate_something(arg)
self.do_something(val)
# ... omitted for brevity ...
Option D
Like Option B or C, but do_something
is injected as a 'full' object, not a bare function. For example:
def func(arg, something_doer=None):
something_doer = something_doer or _something_doer # in production use default
val = _generate_something(arg)
something_doer.do_something(val)
As I said, I would like to know what the best option is, also with regard to 'Pythonicness'. For example, is it 'acceptable' in Python to mock bare functions (rather than objects which contain them)?
mock
library?