0

I need to wrap a class in a mock like so:

Original code:

class _InnerImpl(object):

  def __init__(self, arg1, arg2, arg3):
    # do stuff

I would like to do something like this:

from unittest.mock import patch

def my_wrapper(*args, **kwargs):
  kwargs['arg1'] = gen_next_value()  # change one of the arguments
  return _InnerImpl(*args, **kwargs)  # call the real thing with modified args

def run(user_input):
  with patch(_InnerImpl, my_wrapper):
     some_method(user_input)

Unfortunately the way that patch works, I can't call the "real thing" because it is also called inside the with patch block. This results in infinite recursion loop.

I'm using this in an implementation outside of unit test. So this isn't for unit tests. I've tried various things such as saving __init__ reference, using wraps. Nothing works.

H-N
  • 101
  • 2
  • 8

1 Answers1

0

I suggest not using mocks for things that aren't unit tests. If I understand your example, it seems like what you need is a Factory method pattern https://en.wikipedia.org/wiki/Factory_method_pattern

If you can't modify the code you are patching, try using a different namespace. e.g., given target code a.py

class A(object):
    def __init__(self, v):
        print('A({})'.format(v))

def foo():
    y = A('a')

you could write b.py

from unittest.mock import patch
from a import A,foo
def my_wrapper(*args, **kwargs):
    return A('b')
def bar():
    with patch('a.A', my_wrapper):
        foo()
James Brusey
  • 355
  • 3
  • 11
  • In this case, I don't own the underlying code nor can I change the user-facing interface. So the only option I have is to intercept the call in the middle. – H-N Jun 06 '19 at 03:33
  • Possibly then the answer is to make use of the information here: https://docs.python.org/3.5/library/unittest.mock.html#where-to-patch and to do an import into another namespace `b` prior to patching in namespace `a`. Then the `b` namespace version will still point to the original. – James Brusey Jun 07 '19 at 01:48