'How to mock method of a mocked class
Changed the titel to a more common one. I guess the problem is not that class specific.
I want to mock google.cloud.pubsub_v1.SubscriberClient I want to set a fake return value when calling the pull function of the client.
prod code: from google.cloud import pubsub_v1
def open_subscription() -> None:
with pubsub_v1.SubscriberClient() as subscriber:
logger.info(f'Listening for messages on {config.SUBSCRIPTION_NAME}', {'operation': {'first': True}})
while True:
# get messages
response = subscriber.pull(
request = {
'subscription': config.SUBSCRIPTION_NAME,
'max_messages': config.MAX_MESSAGES
}
)
from the prod code above I want to set the return value for calling the pull method. I am creating a pull-response object in the test code.
test code:
import unittest
from unittest.mock import MagicMock, patch
from app.pubsub import pubsub_service
from google import pubsub_v1
import json
class TestPubSubService(unittest.TestCase):
def create_test_message(self):
message_string = '{"testKey": "testValue"}'
message_json = json.dumps(message_string, indent=2)
message_data = message_json.encode('utf-8')
pubsub_message = pubsub_v1.PubsubMessage()
pubsub_message.data = message_data
received_message = pubsub_v1.ReceivedMessage()
received_message.ack_id = "testId"
received_message.message = pubsub_message
return received_message
def create_test_pull_response(self, received_message):
pull_response = pubsub_v1.PullResponse()
pull_response.received_messages = [received_message]
return pull_response
@patch('app.pubsub.pubsub_service.pubsub_v1.SubscriberClient')
def test_open_subscription(self, mock_subscriber):
test_message = self.create_test_message()
pull_response = self.create_test_pull_response(test_message)
mock_subscriber.return_value.pull.return_value = MagicMock(return_value = pull_response)
pubsub_service.open_subscription()
At least the MagicMock is in place (without using the patch the real subscriber is in place). So basically I would say I mocked the subscriberClient. But I cannot set the return_value for calls to the pull method. But there wont be a pull retur value. All I get is another magicMock created.
I do not get it why it is not working. As most stuff I read we usually have to call 'return_value' on the mock, append the name of either the field or function to be set, append that ones 'return_value' and set a value viea MagicMock. The format should be: mockFirst.return_value.second.return_value.third.return_value = Mock(return_value = the_value_to_return)
Hopefully you can explain me what I am doing wrong. Thanks.
edit: tried also the following ones which where the answers in other posts: Mocking Method Calls In Python Mock a method of a mocked object in Python?
mock_subscriber.pull.return_value = pull_response
mock_subscriber.return_value.pull.return_value = pull_response
none seems to work. the return value of the pull method stays to be a magicMock.
And this is how it looks like in debugging (hovering over response):
Solution 1:[1]
I faced the same issue. But can get idea from the details inside MagicMock.
Try to set return value (based on your screenshot)
mock_subscriber.__enter__().pull.return_value = pull_response
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Brij |