I have the following code:
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = message_class(body)
message.publish()
I want to assert that the Message.publish() method is called. How do I achieve this?
I've already tried the following ways:
Assign message_class to Mock or Mock(). If I debug what message_class(body) returns, it is a Mock, but I don't seem to be able to get the instance and assert it (because the Mock I assign in my test is not the instance used, it is the Type).
Patch Message class with decorator. Whenever I do this it seems like it does not catch it. When I debug what message_class(body) returns its of Message type, not Mock.
Try to mock the __init__ method of message_class in hopes that I can set the instance that is returned whenever the code tries to Instantiate the message. Does not work, throws errors because the __init__ method is not suppose to have a return value.
If you were storing the actual instance, I'd say you could do something like messenger.message.publish.assert_called_once, but since message_class is being stored, it makes it slightly trickier. Given that, you can pull the return_value from the mocked class and check the call that way. Here's how I did it:
Messenger. Note the slight modification to assign message_class to self. I'm assuming you meant to do that, otherwise it wouldn't work without some global funkiness:
'''messenger.py'''
class Message(object):
def __init__(self, body):
self.body = body
def publish(self):
print('message published: {}'.format(self.body))
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
self.message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = self.message_class(body)
message.publish()
Test:
'''test_messenger.py'''
from unittest import mock, TestCase
from messenger import Messenger
class TestMessenger(TestCase):
#mock.patch('messenger.Message')
def test_publish(self, mock_message):
messenger = Messenger()
messenger.publish('test body')
# .return_value gives the mock instance, from there you can make your assertions
mock_message.return_value.publish.assert_called_once()
Related
I have a class that I want to patch in my unittests.
class OriginalClass():
def method_a():
# do something
def method_b():
# do another thing
Now I created another class to patch it with, so the code for patching it is like
class MockClass(OriginalClass):
def method_a():
# This will override the original method and return custom response for testing.
patcher = patch('OriginalClass', new=MockClass)
mock_instance = patcher.start()
This works exactly as I want it to and I can return whatever responses required for my unittests.
Now this issue is when I want to verify that a method is called with the right parameters in the unittests.
I tried
mock_instance.method_a.assert_called_once()
But it fail with error AttributeError: 'function' object has no attribute 'assert_called_once'.
How can I test the method calls here?
AttributeError: 'function' object has no attribute 'assert_called_once'.
Once mock object is created, there is no method_a exists, you have to call once m.method_a() before assert.
m = mock.create_autospec(OriginalClass)
m.method_a()
m.method_a.assert_called_once()
patch mock entire class
I took it as mock the whole class and all its methods, I would take an example from here
https://docs.python.org/3.3/library/unittest.mock-examples.html
Applying the same patch to every test method, Here is my example, patch the entire Primary class as MockPrimay for every methods and every tests, setup or SetupClass could be added for the methods needed, even the whole class is mocked, but not every methods to be used in the tests.
from tests.lib.primary_secondary import Secondary
#mock.patch('tests.lib.primary_secondary.Primary')
class TestSecondaryMockPrimary(unittest.TestCase):
def test_method_d(self, MockPrimary):
MockPrimary().process()
MockPrimary().process.return_value = 1
oc = Secondary()
self.assertEqual(oc.method_d(), 1)
import tests
self.assertIs(tests.lib.primary_secondary.Primary, MockPrimary)
The Primary is needed for the Secondary for this test
class Primary(object):
def __init__(self, param):
self._param = param
def process(self):
if self._param == 1:
self._do_intermediate_process()
self._do_process()
class Secondary(object):
def __init__(self):
self.scl = Primary(1)
def method_d(self):
return self.scl.process
I think wraps can be useful here:
from unittest.mock import patch
class Person:
name = "Bob"
def age(self):
return 35
class Double(Person):
def age(self):
return 5
with patch('__main__.Person', wraps=Double()) as mock:
print(mock.name) # mocks data
print(mock.age()) # runs real methods, but still spies their calls
mock.age.assert_not_called()
Output:
<MagicMock name='Person.name' id='139815250247536'>
5
...
raise AssertionError(msg)
AssertionError: Expected 'age' to not have been called. Called 1 times.
Calls: [call()].
I am trying to test the following method:
def my_method(self, request, context):
context.set_details('Already exists')
context.set_code(grpc.StatusCode.ALREADY_EXISTS)
To test it, I must pass in a request and a context (which is a grpc.ServicerContext object), like so:
import grcp
def test_my_method(self):
request = {"something": "something-else"}
context = grpc.ServicerContext()
my_method(request, context)
# Assert something here
The problem is, I get the following error when I run my tests:
TypeError: Can't instantiate abstract class ServicerContext with abstract methods add_callback, cancel, invocation_metadata, is_active, peer, send_initial_metadata, set_code, set_details, set_trailing_metadata, time_remaining
How can I get a grpc.ServicerContext object? If I can't, how do I test the method?
grpc.ServicerContext is an abstract class defined with the abc module. In your test you need to write your own concrete subclass of it and pass an instance of that to the method you are testing.
I am working with locust and I am working in mimicking the behavior of a user. However I am getting trouble accessing the parent class variable. Any idea how I can pass it?
class User(TaskSet):
some_user = ''
def on_start(self):
self.get_user()
def get_user(self):
some_user = self.client.get...#gets user
#task
class UpdatingUser(TaskSet):
def updating(self):
path = "/posts/" + User.some_user
By the time I get to User.some_user I never have the user.
You've not provided all of the code, but the problem may be that get_user() is setting some_user as an instance attribute somewhere, as in self.some_user = foo.
This will only set some_user for that specific instance of User however (so for Bob, Lisa, Beto, User53, etc.), but not for the User class itself. When accessing some_user with self, as in self.some_user, you set it for the specific instance that's executing those statements, not the class. In updating() you're accessing the class attribute User.some_user, not a specific instance attribute like usr53.some_user. In order to update the class attribute, invariant by default for all instances of User, you ought to be setting it with User.some_user = foo in get_user().
Right now in path = "/posts/" + User.some_user, it's trying to access the class attribute which may never have been set. Because nested classes like UpdatingUser can't access the instances of the nesting class (User) that they're called from, UpdatingUser won't be able to access any some_user set with self or any other instance attributes of User. So the solution would be to have get_user() set the class attribute instead of the instance attribute as described in the previous paragraph.
This answer is a bit late but, if anyone has this issue, the TaskSet has a parent property, which can be used to access the parent's instance variables. The following is what I used for a basic one-time login:
class UserBehaviour(TaskSet):
def on_start(self):
self.token = self.login()
self.headers = {'Authorization': 'Bearer ' + self.token}
def login(self):
with self.client.post("/login", catch_response = True) as response:
return response.json()['token']
#task
class UserTask1(TaskSet):
#task
def get_data(self):
self.client.get("/data", headers = self.parent.headers)
class WebsiteUser(HttpLocust):
task_set = UserBehaviour
What is the best way to implement a class that never throws an AttributeError or TypeError?
The idea is that I have a class like this
class A():
def __init__(self):
self.logger = NeverThrowClass()
def set_logger(self, logger):
self.logger = logger
def do_stuff(self)
self.logger.info('Stuff is being done.')
pass
Whenever certain class methods are classed, we write something to a log file. However if no log file was specified, I still want the class methods to function. I realize I could catch an exception whenever self.logger is accessed, but I would rather just have the default logger attribute be some magical NeverThrowClass() that will accept being called in anyway, and politely do nothing, and return None for any attribute value so that the class will still function fine whether a logger is specified or not.
Something like this, maybe?
class DoNothing(object):
def __getattr__(self, name):
return lambda *args, **kwargs: None
Basically, this class responds to any attribute access with a function that accepts any number of arguments and returns None.
logger = DoNothing()
logger.info("Stuff is being done") # does nothing
Since it's using __getattr__() rather than the lower-level __getattribute__(), you can just throw some regular attributes on there if you want some non-method stuff.
class LoggerNot(DoNothing):
loglevel = 0
Now you have a loglevel attribute that has a reasonable value (i.e. is not a function) if you have code that checks it.
I'm new to python and GAE and I thought python will act as any other OO language, but apparently not. How does __init__(self): function gives me different results in the following code?
class BaseHandler(webapp.RequestHandler):
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
user = User.get_by_key_name(cookie["uid"])
return self._current_user
class SubmitHandler(BaseHandler):
template_values = dict(facebook_app_id=FACEBOOK_APP_ID)
def __init__(self):
#throws error : AttributeError: 'SubmitHandler' object has no attribute 'request'
self.template_values['current_user'] = self.current_user
def get(self):
#this one function is error free
self.template_values['current_user'] = self.current_user
How do I access the class' parent property?
If you look at your SubmitHandler class you'll notice that it indeed does not have a request attribute -- at least, none you set, and none you give the parent class a chance to set. Perhaps what you need to do is call the parentclass __init__ method before you try to access self.current_user.
As a side note, you should realize that the template_values dict you define inside the SubmitHandler class there is a class attribute, and thus shared between all instances of the class. Since you assign it something instance-specific in your __init__, you probably mean for it to be an instance attribute instead. Assign it to self.template_values in your __init__ method.
There's nothing particularly different about Python's object inheritance.
By defining __init__, you have told Python that this is all that needs to be done to initialize the object. You're therefore denying it the chance to run the superclass's initialization code. You need to call super:
def __init__(self, *args, **kwargs):
super(SubmitHandler, self).__init__(*args, **kwargs)
self.template_values['current_user'] = self.current_user
This might however not solve your problem - you're failing to take into account the possibility that self.request is initialized at another point in the program, which is why it works by the time get is called.
self.request and self.response are not set by the class constructor in webapp. They're set later, when the framework calls the handler's initialize method. You can override this, just make sure you call the parent class's initialize before doing anything else.