What I want to do
I have a class with multiple inheritance for which I want to prepare unit test.
Why I want to do this
Assume that I write some program where I have both animals and plants in there. I have many various Animals (so many Animals subclasses), same with plants. This is why I need both animal and plant type. There are many animals and plants species, this is why I have many inheritence in both animals and plants world. Unfortunately, I have one type that is both some plant and animal (e.g. Lion with Oak like attributes - classes A i B in the example). What I would like to do is to mix both plant and animal attributes and methods into just this one type (class C). I know that it sounds ridiculous, but this is my exact goal and I expect mistakes there as it is quite special. This is why I want to have proper testing there so no mistakes are introduced.
First idea
Let's assume that my code looks like this (I am open for C.__init__
refinement suggestions):
inheritance.py
class A:
def __init__(self, p1):
self.p1 = p1
class B:
def __init__(self, p2):
self.p2 = p2
class C(A, B):
def __init__(self, p1, p2):
# I want to execute init methods of both A and B.
A.__init__(self=self, p1=p1)
B.__init__(self=self, p2=p2)
My first idea for unit tests were like this:
test_inheritance.py
import pytest
from mock import Mock, patch
from inheritance import C
class TestC:
def setup(self):
self.mock_c_object = Mock(spec=C)
# patching A.__init__ and B.__init__
self._patcher_a_init_ = patch("inheritance.A.__init__")
self.mock_a_init = self._patcher_a_init_.start()
self._patcher_b_init_ = patch("inheritance.B.__init__")
self.mock_b_init = self._patcher_b_init_.start()
def teardown(self):
self._patcher_a_init_.stop()
self._patcher_b_init_.stop()
@pytest.mark.parametrize("p1", [0, 1])
@pytest.mark.parametrize("p2", ["x", "y"])
def test_c_init(self, p1, p2):
C.__init__(self=self.mock_c_object, p1=p1, p2=p2)
self.mock_a_init.assert_called_once_with(self=self.mock_c_object, p1=p1)
self.mock_b_init.assert_called_once_with(self=self.mock_c_object, p2=p2)
What is the problem
When I tried to run this test, I faced this traceback:
test_inheritance.py:19 (TestC.test_c_init[x-0])
self = <test_inheritance.TestC object at 0x042C0520>, p1 = 0, p2 = 'x'
@pytest.mark.parametrize("p1", [0, 1])
@pytest.mark.parametrize("p2", ["x", "y"])
def test_c_init(self, p1, p2):
> C.__init__(self=self.mock_c_object, p1=p1, p2=2)
test_inheritance.py:23:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
inheritance.py:15: in __init__
A.__init__(self=self, p1=p1)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_mock_self = <MagicMock name='__init__' id='70100424'>, args = ()
kwargs = {'p1': 0, 'self': <Mock spec='C' id='69801632'>}
def __call__(_mock_self, *args, **kwargs):
# can't use self in-case a function / method we are mocking uses self
# in the signature
> _mock_self._mock_check_sig(*args, **kwargs)
E TypeError: _mock_check_sig() got multiple values for argument 'self'
C:\Python38\lib\site-packages\mock\mock.py:1098: TypeError
How I tried to fix this
I suppose in order to fix the problem with mock (multiple self signatures), I have to start using super
in C.__init__
.
I tried to make such update in inheritance.py:
class C(A, B):
def __init__(self, p1, p2):
super(B, C).__init__(p1=p1)
super(A, C).__init__(p2=p2)
Unfortunately, something is wrong with my code:
test_inheritance.py:19 (TestC.test_c_init[x-0])
self = <test_inheritance.TestC object at 0x0414E268>, p1 = 0, p2 = 'x'
@pytest.mark.parametrize("p1", [0, 1])
@pytest.mark.parametrize("p2", ["x", "y"])
def test_c_init(self, p1, p2):
> C.__init__(self=self.mock_c_object, p1=p1, p2=2)
test_inheritance.py:23:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <Mock spec='C' id='68478408'>, p1 = 0, p2 = 2
def __init__(self, p1, p2):
> super(B, C).__init__(p1=p1)
E TypeError: descriptor '__init__' of 'object' object needs an argument
inheritance.py:13: TypeError
Could you help me please? Honestly, I have only used super
for single inheritance till now, therefore I have not had problems like this one. Thank you in advance.