jeudi 26 décembre 2019

Python - Unit Testing Patch

I'm having some issues getting @patch to work with my unit tests, after patching an import the mock doesn't seem to be picked up and the 'regular' class is used instead

The class and method I'm trying to test are shown below (simplified for sake of the question)

from sila2lib.sila_server import SiLA2Server
# ... snip ...

class DeviceService:

def __init__(self, central_message_queue: asyncio.Queue, config: Config):

    self.central_message_queue: asyncio.Queue = central_message_queue
    self.logger = logging.getLogger('GWLogger')

    # ...... snip ......

async def start_device_server(self, tag_config: dict) -> asyncio.Queue:

    # Message queue used for passing messages to running device features (instrument readings)
    name = tag_config["Name"]
    uuid = tag_config["UUID"]
    cfg = tag_config["FeatureConfig"]

    # SiLA Server Setup [This is what I want to mock]
    self.device_server = SiLA2Server(name=name,
                                     description="Provides Device specific functions",
                                     server_uuid=uuid,
                                     port=self.device_server_port,
                                     ip=self.device_server_address,
                                     simulation_mode=False,
                                     key_file=None,
                                     cert_file=None)

    # ........ snip .......

And an example test - all I want to do is swap out the SilaServer with a MagicMock so I can verify a method has been called with the correct params

import asynctest, asyncio
from tests.util.MockConfig import build_mock_config
from unittest.mock import patch, MagicMock
from services.device.DeviceService import DeviceService

class DeviceServiceTests(asynctest.TestCase):

@patch("services.device.DeviceService.SiLA2Server")
async def test_device_info_load(self, mock_sila_server_class):

    mock_sila_server_instance = MagicMock()
    mock_sila_server_class.return_value = mock_sila_server_instance
    message_queue = asyncio.Queue()
    device_service = DeviceService(message_queue, build_mock_config())
    device_service.logger = MagicMock()

    await device_service.start_device_server(empty_tag_config)

    # Test feature has been set
    mock_sila_server_instance.add_feature.assert_called_with(data_path='',
                                                             feature_id='DeviceInfo',
                                                             servicer=None)

    # Check that server was started
    mock_sila_server_instance.run.assert_called_with(block=False)

And project structure

Project Structure

The test runs and fails as the mock isn't being used and I get an assertion exception as you'd expect, adding a breakpoint and examining the device_service is using the actual class

Var inspect

I feel it's something really obvious but I just can't see it, I have other similar tests that work fine with @patch decorators but there doesn't seem to be any difference in how its applied in those tests and this one

Any help is really appreciated

Aucun commentaire:

Enregistrer un commentaire