1

I want to test a class created with default parameters by replacing the value of the default parameter during unit testing.

For example, I want the following line (throughout the code) obj = SomeClass()

To look like it was called with a parameter

obj = SomeClass(overiden_parameter)

One solution might be to create simple subclass:

``` def OriginalClass(object):

def __init_(some_param="default_value"):
    ...

```

``` def MockedOriginalClass(OriginalClass):

def __init_():
    super(MockedOriginalClass, self).__init__("some_other_value)
    ...

```

How to a mock/patch OriginalClass to be MockedOriginalClass thoughout the code? Keep in mind that I do want to keep functionality of the original class, the only one thing I want to change is it's default __init__ parameter.

I feel this is a very simple thing to do with Mocking, I just didn't quite figure how to do it.

I found out about this question: Python unittest mock: Is it possible to mock the value of a method's default arguments at test time?

It's very close but I don't think the same trick can be applied to the __init__ method.

Rastikan
  • 517
  • 5
  • 18
  • You can't just mock `SomeClass` and then have the mock act as if the parameter was passed in? – Martijn Pieters May 29 '18 at 17:08
  • I think you might be right, I'm looking into how to mock/patch existing usage of `SomeClass` with one that simply patch one default input parameter. – Rastikan May 29 '18 at 18:03

2 Answers2

1

One way to do this is by mocking the whole class for you specific tests like this:

Example: I have a class SomeClass that I want to mock. My mocking class name is MockSomeClass that will mock class SomeClass.

class MockSomeClass(SomeClass):
    '''
    Mock Class
    '''
    def __init__(overiden_parameter):
        self.overiden_parameter = overiden_parameter

So during the test, you will use the mock class which has overridden functionality and while the other functions behavior will remain same(inheritance).

Patching

mock_some_class_obj = MockSomeClass()

@mock.patch('SomeClass', return_value=mock_some_class_obj)
def test1(self, mock_some_class_obj):
'''
Test 1
'''
    obj = SomeClass()

catch so in the code whenever you will create the object of SomeClass the object of the mock class will be returned. in the mock class, you can add your own functionality.

Irtiza
  • 173
  • 4
  • 16
  • 1
    How is this suppose to help with existing library? Are you expecting that we would replace all existing code to use this new class? You might have part of the answer, what's missing is how to 'patch' the existing class with this new one. – Rastikan May 29 '18 at 18:01
  • Is `MockSomeClass` subclassing the original class or `mock.Mock` ? – Rastikan May 29 '18 at 18:30
  • it is subclassing the original class – Irtiza May 29 '18 at 19:19
  • the approach that I have described above will only override the functionality of the __init__ method in the subclass, while the other methods/functions will behave same as in the main/base class. – Irtiza May 29 '18 at 19:22
  • This is no good, I do need the class as is, just need to tweak it's behaviour by changing the init default parameter value. – Rastikan May 29 '18 at 19:26
  • "I do need the class as is, just need to tweak its behavior by changing the init default parameter value" as you said you just want to tweak the behavior of the __init__ method, this is what I have done in the example given above, other methods/functions of class will behave same as in the base class – Irtiza May 29 '18 at 19:38
0

Look at @Martinj Pieters comment, but alternatively, you could use monkey patching https://en.wikipedia.org/wiki/Monkey_patch which is supported in pytest https://docs.pytest.org/en/documentation-restructure/how-to/monkeypatch.html to override the __init__ method.

Josep Valls
  • 5,483
  • 2
  • 33
  • 67