How to mock googleapiclient.discovery.build

Viewed 1735

I am trying to mock the result of API call made to compute engine to list VMs. But unfortunately couldn't mock an exact function.

I've tried using PATCH and MOCK methods to mock specific calls made, still unsuccessful

code.py file looks likes this

import googleapiclient.discovery
import logging

class Service:
    def __init__(self, project, event):
        self.project_id = project
        self.compute = googleapiclient.discovery.build('compute', 'v1',
                                                       cache_discovery=False)
        self.event = event
        self.zones = self._validate_event()

    def _validate_event(self):
        if "jsonPayload" not in self.event:
            zones = self.compute.zones().list(
                project=self.project_id).execute()['items']

        else:
            zones = self.compute.zones().get(project=self.project_id,
                                             zone=self.event["jsonPayload"]
                                             ["resource"]["zone"]).execute()

        logging.debug(f"Identified Zones are {zones}")
        return [zone["name"] for zone in zones]

My test file looks like this

# in-built
from unittest import TestCase
from unittest.mock import patch

# custom
import code


class TestServiceModule(TestCase):
    def setUp(self):
        self.project_id = "sample-project-id"

    @patch('code.googleapiclient.discovery')
    def test__validate_event_with_empty_inputs(self, mock_discovery):
        mock_discovery.build.zones.list.execute.return_value = {"items": [
            {
                "name": "eu-west-1"
            }
        ]}

        obj = code.Service(event={}, project=self.project_id)

        print(obj.zones)


In the above test case, I Expected to see "eu-west-1" as the value when I print obj.zones

1 Answers

You didn't mock the googleapiclient.discovery.build method correctly. Here is the unit test solution:

E.g.

code.py:

import googleapiclient.discovery
import logging


class Service:
    def __init__(self, project, event):
        self.project_id = project
        self.compute = googleapiclient.discovery.build('compute', 'v1', cache_discovery=False)
        self.event = event
        self.zones = self._validate_event()

    def _validate_event(self):
        if "jsonPayload" not in self.event:
            zones = self.compute.zones().list(project=self.project_id).execute()['items']
        else:
            zones = self.compute.zones().get(project=self.project_id,
                                             zone=self.event["jsonPayload"]["resource"]["zone"]).execute()

        logging.debug(f"Identified Zones are {zones}")
        return [zone["name"] for zone in zones]

test_code.py:

from unittest import TestCase, main
from unittest.mock import patch
import code


class TestService(TestCase):
    def setUp(self):
        self.project_id = "sample-project-id"

    @patch('code.googleapiclient.discovery')
    def test__validate_event_with_empty_inputs(self, mock_discovery):
        # Arrange
        mock_discovery.build.return_value.zones.return_value.list.return_value.execute.return_value = {
            "items": [{"name": "eu-west-1"}]}

        # Act
        obj = code.Service(event={}, project=self.project_id)

        # Assert
        mock_discovery.build.assert_called_once_with('compute', 'v1', cache_discovery=False)
        mock_discovery.build.return_value.zones.assert_called_once()
        mock_discovery.build.return_value.zones.return_value.list.assert_called_once_with(project='sample-project-id')
        mock_discovery.build.return_value.zones.return_value.list.return_value.execute.assert_called_once()
        self.assertEqual(obj.zones, ["eu-west-1"])


if __name__ == '__main__':
    main()

unit test result with coverage report:

.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK
Name                                      Stmts   Miss  Cover   Missing
-----------------------------------------------------------------------
src/stackoverflow/56794377/code.py           14      1    93%   16
src/stackoverflow/56794377/test_code.py      16      0   100%
-----------------------------------------------------------------------
TOTAL                                        30      1    97%

Versions:

  • google-api-python-client==1.12.3
  • Python 3.7.5
Related