I have a top level script that creates instances of objects and executes instance's methods. I am very confused as how I can execute fetcher's methods from within the alarm_handler file. Specifically, line 'status = fetcher.get_status' below. Hopefully this makes sense as to what I'm asking. Please let me know if I can clarify anything.
***file: master***
import fetcher
import alarm_handler
fetcher = fetcher.Fetcher()
alarms = alarm_handler.AlarmHandler()
site_status = alarms.compare_status()
***file: fetcher***
class Fetcher(object):
def fetch(self)
fetch a bunch of internet data
def get_status(self)
fetch some other internet data
***file: alarm_handler***
from master import fetcher
class AlarmHandler(object):
def compare_status (self)
status = fetcher.get_status()
status_comparison = status comparison stuff
return status_comparison
You are creating a circular import. Don't.
Perhaps you wanted to pass the fetcher instance to the AlarmHandler.compare_status() method instead?
import fetcher
import alarm_handler
fetcher = Fetcher()
alarms = AlarmHandler()
site_status = alarms.compare_status(fetcher)
or perhaps pass it in when you create the AlarmHandler() instance:
import fetcher
import alarm_handler
fetcher = Fetcher()
alarms = AlarmHandler(fetcher)
site_status = alarms.compare_status()
Related
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):
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
I am new to Python, so I apologize if this is a duplicate or overly simple question. I have written a coordinator class that calls two other classes that use the kafka-python library to send/read data from Kafka. I want to write a unit test for my coordinator class but I'm having trouble figuring out how to best to go about this. I was hoping that I could make an alternate constructor that I could pass my mocked objects into, but this doesn't seem to be working as I get an error that test_mycoordinator cannot be resolved. Am I going about testing this class the wrong way? Is there a pythonic way I should be testing it?
Here is what my test class looks like so far:
import unittest
from mock import Mock
from mypackage import mycoordinator
class MyTest(unittest.TestCase):
def setUpModule(self):
# Create a mock producer
producer_attributes = ['__init__', 'run', 'stop']
mock_producer = Mock(name='Producer', spec=producer_attributes)
# Create a mock consumer
consumer_attributes = ['__init__', 'run', 'stop']
data_out = [{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
mock_consumer = Mock(
name='Consumer', spec=consumer_attributes, return_value=data_out)
self.coor = mycoordinator.test_mycoordinator(mock_producer, mock_consumer)
def test_send_data(self):
# Create some data and send it to the producer
count = 0
while count < 3:
count += 1
testName = 'test' + str(count)
self.coor.sendData(testName , None)
And here is the class I am trying to test:
class MyCoordinator():
def __init__(self):
# Process Command Line Arguments using argparse
...
# Initialize the producer and the consumer
self.myproducer = producer.Producer(self.servers,
self.producer_topic_name)
self.myconsumer = consumer.Consumer(self.servers,
self.consumer_topic_name)
# Constructor used for testing -- DOES NOT WORK
#classmethod
def test_mycoordinator(cls, mock_producer, mock_consumer):
cls.myproducer = mock_producer
cls.myconsumer = mock_consumer
# Send the data to the producer
def sendData(self, data, key):
self.myproducer.run(data, key)
# Receive data from the consumer
def getData(self):
data = self.myconsumer.run()
return data
There is no need to provide a separate constructor. Mocking patches your code to replace objects with mocks. Just use the mock.patch() decorator on your test methods; it'll pass in references to the generated mock objects.
Both producer.Producer() and consumer.Consumer() are then mocked out before you create the instance:
import mock
class MyTest(unittest.TestCase):
#mock.patch('producer.Producer', autospec=True)
#mock.patch('consumer.Consumer', autospec=True)
def test_send_data(self, mock_consumer, mock_producer):
# configure the consumer instance run method
consumer_instance = mock_consumer.return_value
consumer_instance.run.return_value = [
{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
coor = MyCoordinator()
# Create some data and send it to the producer
for count in range(3):
coor.sendData('test{}'.format(count) , None)
# Now verify that the mocks have been called correctly
mock_producer.assert_has_calls([
mock.Call('test1', None),
mock.Call('test2', None),
mock.Call('test3', None)])
So the moment test_send_data is called, the mock.patch() code replaces the producer.Producer reference with a mock object. Your MyCoordinator class then uses those mock objects rather than the real code. calling producer.Producer() returns a new mock object (the same object that mock_producer.return_value references), etc.
I've made the assumption that producer and consumer are top-level module names. If they are not, provide the full import path. From the mock.patch() documentation:
target should be a string in the form 'package.module.ClassName'. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when the decorated function is executed, not at decoration time.
I am trying to use the sendMessage function provided by WebSocketServerProtocol in a seperate file/class but getting exceptions.
class MyServerProtocol(WebSocketServerProtocol):
def onMessage(self, payload, isBinary):
#input = payload
#print payload
# echo back message verbatim
#self.sendMessage(payload, isBinary)
cg = coreg.DataGatherCg
cg.test(cg())
in coreg:
from appserver import MyServerProtocol
from autobahn.twisted.websocket import WebSocketServerProtocol, \
WebSocketServerFactory
class DataGatherCg(MyServerProtocol):
def test(self):
MyServerProtocol.send(self,'test',False)
I am getting the error:
(<type 'exceptions.AttributeError'>): 'DataGatherCg' object has no attribute 'state')
I am trying to put it in a seperate file and class as the class will eventually be huge and I would prefer to have them separate so I can keep track of everything.
Any suggestions on how to do this?
UPDATE: Can someone provide an example of how to "...split a class due to complexity, create a mix-in class and inherit from it."
In my Main.py
I have put
from carNum import *
vehicleID =0
vehicleID = carNum()
print ("Object Created")
Here is my carNum class
class carNum:
def __init__(self):
speedlist = []
But when I run this I am getting 'module' object is not callable
Thank you very much in advance
I really hope you guys can help me out
import can used to import modules, that may contain classes as well functions and other stuff, and not only to import classes.
In python you can put multiple classes in the same file, as well as the main program. For example you can put in your main.py (which is your module), the following:
class carNum(object):
def __init__(self):
# initialize some attribute
self.speedlist = []
myobject = carNum()
Print("Object Created")
I left out this part:
vehicleID =0
vehicleID = carNum()
vehicleID = vehicleID + 1
since to me it doesn't make any sense.
You can also put the cardNum class into a separate module (i.e: cardnum.py) and then import it in your main module (i.e: main.py) using:
from cardnum import cardNum
My (simplified) project layout is as follows:
/__init__.py
/test.py
/lib/__init__.py
/lib/client.py
my test.py is simply:
import lib.client
A = client()
A.Test()
and my lib\client.py begins as follows:
import ui #(another class in the lib dir)
class client(object):
"""
(Blah)
"""
UI = None
def __init__():
UI = ui()
def Test():
print "Success"
When I attempt to run test.py, I can step into the code and see that the definitions in client are parsed, however, when I get to the line where I instantiate a client, I get the following exception:
NameError: name 'client' is not defined
if I change that line to be:
A = lib.client()
Then I get
'module' object is not callable
What am I missing?
the lib.client object you have after import lib.client is the module, not the class. To instantiate the class you need to call the class in the module object:
A = lib.client.client()
or, as #rantanplan said, import the class from the module
from lib.client import client
A = client()
I just understood that you do the imports the Java way.
In python when you do :
import lib.client
You don't make available all the definitions in that module. You just
made available the actual module - the client.py
So either you keep the import scheme as you have now and do
import lib.client
A = lib.client.client()
or
from lib.client import client
A = client()
Also I suggest you name your python classes with capitalized camelcase
i.e.
class Client(object):
As it is the python convention.