I apologize for the confusing title, I wasn't sure there was a better way to describe the problem. I have a python library with the following structure:
library/
src/
code/
__init__.py
baseclass.py
helpers.py
class1.py
tests/
__init__.py
test_library.py
I am attempting to test a function in a class in baseclass.py. The function in the class in baseclass.py returns class objects from class1.py as shown below: baseclass.py:
from class1 import DeviceClass
class LibraryBuilder:
def __init__(self, user, password):
......
def get_devices(self):
devlist = helpers.call_api('api_url', 'post', header, json)
#Return a list of dictionaries
for dev in devlist:
if dev = "DeviceType":
return DeviceClass(dev, self)
test_library.py
import pytest
from unittest.mock import patch, Mock
from library.baseclass import LibraryBuilder
import library
from library.class1 import DeviceClass
class TestDeviceList(object):
@pytest.fixture()
def api_mock(self, caplog):
self.mock_api_call = patch('library.helpers.call_api', autospec=True)
self.mock_api = self.mock_api_call.start()
self.mock_api.return_value.ok = True
self.library_obj = library.baseclass.LibraryBuilder('sam@mail.com', 'pass')
yield
self.mock_api_call.stop()
@patch.object('baseclass.class1', 'DeviceClass', autospec=True)
def test_get_devices_all(self, caplog, dev_mock, api_mock):
self.mock_api.return_value = return_dict
devs = self.library_object.get_devices()
dev_mock.assert_called_with(return_dict, self.library_object)
The test fails because 'device_object' is never called. When I debug, I see that the device_patch object that is created isn't the mocked object, its the actual DeviceClass object.
I've tried to reference the device_object path to patch.object('library.baseclass', 'DeviceClass', autospec=True)
. I've tried variations of the imported classes because I believe this is related to the thread below but I can't figure out where I am going wrong:
Why python mock patch doesn't work?
The call_api mock works as it should. The library_object returns the actual instantiated class based off of the call_api mocked return_value
I just refactored the code from a single file to this configuration and the test was passing before that. Any ideas on what I'm missing?
EDIT
I debugged even further and I believe it has to do with DeviceClass
inheriting from DeviceBaseClass
so that device_class.py looks like:
class DeviceBaseClass(object):
def __init__(self, details, manager):
self.details = {}
..............
class DeviceClass(DeviceBaseClass):
def __init__(self, details, manager):
super(DeviceClass, self).__init__(details, manager)
so now I am getting the message TypeError: super() argument 1 must be type not MagicMock
. I'm guessing since I'm mocking DeviceClass the mocked class is being called in the super() method. I've seen a few other posts on this but haven't found a solution. Am I missing something obvious or am I on the completely wrong track?