Is there a way to mock isinstance() of an object in python? - python

I want to write a mock for a library object without inheriting from it in order to properly test, however without having to stub all non used functions of the original object.
To be specific I want to write a ContextMock for the invoke library.
class ContextMock:
...
The main problem here is that I therefor call a #task function which then calls my code that I want to test. However the #task decorator checks whether the context object is an instance of a Context, like this:
def __call__(self, *args, **kwargs):
# Guard against calling tasks with no context.
if not isinstance(args[0], Context):
err = "Task expected a Context as its first arg, got {} instead!"
# TODO: raise a custom subclass _of_ TypeError instead
raise TypeError(err.format(type(args[0])))
Therefor my question is, can I somehow change the isinstance function of my ContextMock, or make it look like its an instance of Context without inheriting its attributes?
Or would it be possible to somehow mock the isinstance function?
How does the default implementation of instancecheck work? Is there perhabs a baseclass attribute that can be overwritten?
I already tried to provide a custom metaclass with an custom instancecheck function, which of course does not work as the instancecheck of the Context is called, right?
Also Note that I'm well aware that any hacky solution should not belong in production code, and is only used for testing.
Edit:
To add a generic example of what I want to archive:
class Context:
pass
class ContextMock:
pass
mock = ContextMock
... do magic with mock
assert isinstance(mock, Context)

Related

Python unittest mock: Is it possible to mock the value of the __init__'s default arguments at test time?

I want to test a class created with default parameters by replacing the value of the default parameter during unit testing.
For example, I want the following line (throughout the code)
obj = SomeClass()
To look like it was called with a parameter
obj = SomeClass(overiden_parameter)
One solution might be to create simple subclass:
```
def OriginalClass(object):
def __init_(some_param="default_value"):
...
```
```
def MockedOriginalClass(OriginalClass):
def __init_():
super(MockedOriginalClass, self).__init__("some_other_value)
...
```
How to a mock/patch OriginalClass to be MockedOriginalClass thoughout the code? Keep in mind that I do want to keep functionality of the original class, the only one thing I want to change is it's default __init__ parameter.
I feel this is a very simple thing to do with Mocking, I just didn't quite figure how to do it.
I found out about this question:
Python unittest mock: Is it possible to mock the value of a method's default arguments at test time?
It's very close but I don't think the same trick can be applied to the __init__ method.
One way to do this is by mocking the whole class for you specific tests like this:
Example:
I have a class SomeClass that I want to mock. My mocking class name is MockSomeClass that will mock class SomeClass.
class MockSomeClass(SomeClass):
'''
Mock Class
'''
def __init__(overiden_parameter):
self.overiden_parameter = overiden_parameter
So during the test, you will use the mock class which has overridden functionality and while the other functions behavior will remain same(inheritance).
Patching
mock_some_class_obj = MockSomeClass()
#mock.patch('SomeClass', return_value=mock_some_class_obj)
def test1(self, mock_some_class_obj):
'''
Test 1
'''
obj = SomeClass()
catch so in the code whenever you will create the object of SomeClass the object of the mock class will be returned. in the mock class, you can add your own functionality.
Look at #Martinj Pieters comment, but alternatively, you could use monkey patching https://en.wikipedia.org/wiki/Monkey_patch which is supported in pytest https://docs.pytest.org/en/documentation-restructure/how-to/monkeypatch.html to override the __init__ method.

Subclassing Mock in Python 2.7

I have a set of unit tests which will repeatedly be using a certain cooperator class Rental that I want to mock, with the same arguments passed every time. To make this easier, I want to make a subclass of mock.Mock and pass the arguments on creation. Here's the code:
class RentalMock(Mock):
def __call__(self, *args, **kwargs):
super(RentalMock, self).__call__(*args, spec_set=Rental, **kwargs)
self.get_points.return_value=0
return self
The problem is, when I instantiate this class, that override has no visible effect. And trying to override it here also doesn't work.
> a = RentalMock()
> a.get_points()
<RentalMock name='mock.get_points' id='4447663888'>
> a.get_points.return_value = 0
> a.get_points()
<RentalMock name='mock.get_points' id='4447663888'>
> a.configure_mock(**{"get_points.return_value":0})
> a.get_points()
<RentalMock name='mock.get_points' id='4447663888'>
I'm thoroughly confused. I've tried three methods, all taken directly from the docs, and none seem to work. When I pass these arguments directly to an instance of Mock, they work fine. What am I missing?
You are overriding __call__ when it looks like you want to override __init__. Subclassing can often get involved, especially with something as already intricate as Mock. Perhaps a factory function would be simpler.

Can I add an instance method to a Python "Mock" object?

I would like to create a mock.Mock() object, then add a method called session that acts like an instance method, which is passed a self reference to the mock object, allowing the method to add state to the mock object. Is this possible (without manually using types.MethodType, e.g., using mock's built-in API), or should I just find a way around it?
Note, I found this question, which is for Ruby and seems to cover something similar, if not the same thing. Unfortunately, I don't know Ruby very well at all.
mock_answer = Mock()
def session():
mock_answer.b = 1
mock_answer.session = session
mock_answer.session()
print(mock_answer.b) # 1
You don't need self actually.
If you want to enhance the capabilities of the mock.Mock class, just subclass Mock and add your own methods.
class MyMock(Mock):
def session(self):
# Save session data here?
The mock documentation explains that when a new mock is to be created, it will be the same type as the parent. This means that the session function will also be available on any other mocks which are created during mocking.
This doesn't cover the case where you need to dynamically attach a session function to an existing mock object.

Redirect method call and pass caller along automatically

I'm building a modular app and I wanted all Objects of a certain type to be able to call a management object, and automatically have their own instance passed along.
Scenario:
My application consists of a framework and plugins that are being loaded at runtime.
One of these plugins provides functionality that operates in a separate contexts for each plugin. Simply put: It receives the instance of the caller plugin and only operates with data associated with this plugin.
In order to avoid confusion in the following description, lets refer to the callee as management object and to the caller as worker object.
There is going to be one management object and multiple plugins:
Plugin + : 1 Management Object
I would like the worker object to be able to access the management functionality, without the need to specify the instance of the worker instance explicitly in the parameter list.
Instead, I'd like the management methods to look, as if they belonged to the worker object - so that the passing of the caller argument is transparent and implicit.
One possibility would be, to register all new management methods with the worker class directly. However, I don't like this "namespace pollution". Instead, I'd like them to be accessible via an attribute so that the meaning is clear.
Keep in mind, that this behaviour is added at runtime, and I do not wish to modify the Plugin class itself. Also, multiple plugins may already have been instantiated at that time, but I need this to work for all current and future instances.
The idea I've come up with, is to combine the descriptor __get__ and __getattr__ methods in one object.
The __get__ method will be used, to determine the instance of the caller.
The __getattr__ method will be used, to dynamically wrap the method that is being supposed to be called from the management object.
The code I've come up with looks like this:
my_management_object = getItHere()
class Wrapper(object):
def __init__(self):
self._caller = None
def __getattr__(self, name):
method = getattr(my_management_object, name)
def wrapper(*args, **kwargs):
return method(self._caller, *args, **kwargs)
return wrapper
def __get__(self, caller, type):
self._caller = caller
return self
MyPluginClass._manage = Wrapper()
So now, I can do:
obj = MyPluginClass()
obj._manage.doSomethingForMe()
#vs:
getMyManagementObject().doSomethingForMe(obj)
I have tested it and it seems to work.
I was wondering whether there are any pitfalls in this method or whether there are more pythonic ways to do this. I'm pretty new to the Descriptor stuff so I may have overlooked something.
If all you're doing is accessing attributes, use a descriptor. It appears that you're implementing a descriptor-like design and calling it a "Wrapper". A descriptor will probably be slightly simpler and more consistent with all the other places in Python that use descriptors.
http://docs.python.org/reference/datamodel.html#descriptors
Making this a more typical descriptor class may save you some work.

Python/Django: Adding custom model methods?

Using for example
class model(models.Model)
....
def my_custom_method(self, *args, **kwargs):
#do something
When I try to call this method during pre_save, save, post_save etc, Python raises a TypeError; unbound method.
How can one add custom model methods which can be executed in the same way like model.objects.get(), etc?
Edit: tried using super(model, self).my_custom_method(*args, **kwargs) but in that case Python says that model does not have attribute my_custom_method
How are you calling this method? You have defined an instance method, which can only be called on an instance of the class, not the class itself. In other words, once you have an instance of model called mymodelinstance, you can do mymodelinstance.my_custom_method().
If you want to call it on the class, you need to define a classmethod. You can do this with the #classmethod decorator on your method. Note that by convention the first parameter to a classmethod is cls, not self. See the Python documentation for details on classmethod.
However, if what you actually want to do is to add a method that does a queryset-level operation, like objects.filter() or objects.get(), then your best bet is to define a custom Manager and add your method there. Then you will be able to do model.objects.my_custom_method(). Again, see the Django documentation on Managers.
If you are implementing a Signal for your model it does not necessarily need to be defined in the model class only. You can define it outside the class and pass the class name as the parameter to the connect function.
However, in your case you need the model object to access the method.

Categories