I am testing a class that inherits from another one very complex, with DB connection methods and a mess of dependences. I would like to mock its base class so that I can nicely play with the method defined in the subclass, but in the moment I inherit from a mocked class, the object itself turns a mock and loses all its methods.
How can I mock a superclass?
More or less the situation can be summed up in this:
import mock
ClassMock = mock.MagicMock()
class RealClass(ClassMock):
def lol(self):
print 'lol'
real = RealClass()
real.lol() # Does not print lol, but returns another mock
print real # prints <MagicMock id='...'>
This is a simplified case. What is actually happening is that RealClass extends AnotherClass, but I managed to intercept the AnotherClass and replace it with a mock.
This is something I've been struggling with for a long time, but I think I've finally found a solution.
As you already noticed, if you try to replace the base class with a Mock, the class you're attempting to test simply becomes the mock, which defeats your ability to test it. The solution is to mock only the base class's methods rather than the entire base class itself, but that's easier said than done: it can be quite error prone to mock every single method one by one on a test by test basis.
What I've done instead is created a class that scans another class, and assigns to itself Mock()s that match the methods on the other class. You can then use this class in place of the real base class in your testing.
Here is the fake class:
class Fake(object):
"""Create Mock()ed methods that match another class's methods."""
#classmethod
def imitate(cls, *others):
for other in others:
for name in other.__dict__:
try:
setattr(cls, name, Mock())
except (TypeError, AttributeError):
pass
return cls
So for example you might have some code like this (apologies this is a little bit contrived, just assume that BaseClass and SecondClass are doing non-trivial work and contain many methods and aren't even necessarily defined by you at all):
class BaseClass:
def do_expensive_calculation(self):
return 5 + 5
class SecondClass:
def do_second_calculation(self):
return 2 * 2
class MyClass(BaseClass, SecondClass):
def my_calculation(self):
return self.do_expensive_calculation(), self.do_second_calculation()
You would then be able to write some tests like this:
class MyTestCase(unittest.TestCase):
def setUp(self):
MyClass.__bases__ = (Fake.imitate(BaseClass, SecondBase),)
def test_my_methods_only(self):
myclass = MyClass()
self.assertEqual(myclass.my_calculation(), (
myclass.do_expensive_calculation.return_value,
myclass.do_second_calculation.return_value,
))
myclass.do_expensive_calculation.assert_called_once_with()
myclass.do_second_calculation.assert_called_once_with()
So the methods that exist on the base classes remain available as mocks you can interact with, but your class does not itself become a mock.
And I've been careful to ensure that this works in both python2 and python3.
This should work for you.
import mock
ClassMock = mock.MagicMock # <-- Note the removed brackets '()'
class RealClass(ClassMock):
def lol(self):
print 'lol'
real = RealClass()
real.lol() # Does not print lol, but returns another mock
print real # prints <MagicMock id='...'>
You should'nt pass an instance of the class as you did. mock.MagicMock is a class, so you pass it directly.
In [2]: inspect.isclass(mock.MagicMock)
Out[2]: True
I was facing a similar problem and was able to do this via #patch.object. See examples for patch decorators in the official python doc.
class MyTest(unittest.TestCase):
#patch.object(SomeClass, 'inherited_method')
def test_something(self, mock_method):
SomeClass.static_method()
mock_method.assert_called_with()
Just exemplifying #Akash's answer, which was the one that in fact solved my inheritance mock challenge:
#patch.object(SomeClassInheritingAnother, "inherited_method")
def test_should_test_something(self, mocked_inherited_method, mocker, caplog):
#Mocking an HTTP result status code
type(mocked_inherited_method.return_value).status_code = mocker.PropertyMock(return_value=200)
#Calling the inherited method, that should end up using the mocked method
SomeClassInheritingAnother.inherited_method()
#Considering that the request result is being logged as 'Request result: {response.status_code}'
assert "Request result: 200" in caplog.text
Related
This would be the layout
some_function.py
def some_function():
print("some_function")
some_library.py
from some_function import some_function
class A:
def xxx(self):
some_function()
main.py
from some_library import A
from some_function import some_function
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
some_function = new_some_function
a = A()
a.xxx()
In the class A, the method xxx, calls some_function, so is it possible to override it with something else, without re-implementing the entire class?
I think you are looking for monkey patching (means changing classes/modules dynamically while running). This way you don't need to overwrite the class A and use inheritance as suggested by other comments - you said you don't want that, so try this solution:
import some_class # import like this or will not work (cos of namespaces)
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
# Import and use like this, other ways of import will not work.
# Because other way imports method to your namespace and then change it in your namespace,
# but you need to change it in the original namespace
some_class.some_function = new_some_function
That way replace the original method and even other classes will use it then. Be careful, if the original method is a class/instance method, you need to create new function with proper params, like this:
def new_some_function(self):
# for instance methods, you may add other args, but 'self' is important
def new_some_function(cls):
# for class methods, you may add other args, but 'cls' is important
You provide very little information about your use case here. As one of the comments points out, this might be a case for inheritance. If you are in a testing context, you may not want to use inheritance though, but you might rather want to use a mock-object.
Here is the inheritance version:
from some_library import A
def new_some_function():
print("new_some_function")
class B(A):
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
Note, how class B derives from class A through the class B(A) statement. This way, class B inherits all functionality from A and the definition of class B only consists of the parts where B differs from A. In your example, that is the fact that the xxx method should call new_some_function instead of some_function.
Here is the mock version:
from unittest import mock
from some_library import A
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
with mock.patch('some_library.some_function') as mock_some_function:
mock_some_function.side_effect = new_some_function
a = A()
a.xxx()
As mentioned above this approach is mostly useful if you are in a testing context and if some_function does something costly and/or unpredictable. In order to test code that involves a call to some_function, you may temporarily want to replace some_function by something else, that is cheap to call and behaves in a predictable way. In fact, for this scenario, replacing some_function by new_some_function might even be more than what is actually needed. Maybe, you just want an empty hull that can be called and that always returns the same value (instead of the side_effect line, you can specify a constant .return_value in the above code example). One of the key functionalities of mock objects is that you can later check if that function has been called. If testing is your use case, I would very much recommend looking at the documentation of the python mock module.
Note that the example uses the mock.patch context manager. This means that within the managed context (i.e. the block inside the with-statement) some_library.some_function is replaced by a mock object, but once you leave the managed context, the original functionality is put back in place.
You may just create another class and override the method you need.
Just as an example:
class myInt(int):
def __pow__(self, x):
return 0
a = myInt(10)
a+10 # 20
a**2 # 0
In this case a is an int and has access to all the method of the int class, but will use the __pow__ method I've defined.
What you need is inheritance, You can subclass a class and with super method you can inherit all the parent class functions. If you want to override parent class functions, you just need to provide a different implementation by the same name in child class.
from some_library import A
from some_function import some_function
def new_some_function():
print("new_some_function")
class B(A):
def __init__(*args, **kwargs):
super().__init__(self)
pass
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
Output:
new_some_function
you syntax may differ depending upon the python version.
In python3
class B(A):
def __init__(self):
super().__init__()
In Python 2,
class B(A):
def __init__(self):
super(ChildB, self).__init__()
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.
I am bit lost while writing the test case for UserCompanyRateLimitValidation class. I am finding difficulty in mocking the class which is being instantiated from inside this class.
class UserCompanyRateLimitValidation:
def __init__(self, user_public_key):
self.adapter = UserAdapter(user_public_key)
container = self.adapter.get_user_company_rate_limit()
super(UserCompanyRateLimitValidation, self).__init__(container,\
UserCompanyRateLimitValidation.TYPE)
I have to test this class. I have written test case something like this. I have tried to mock the UserAdapter class but I am not able to do so completely.
def test_case_1():
self.user_public_key = 'TEST_USER_PUBLIC_KEY_XXXXXX1234567890XXXXX'
UserAdapter_mock = mock(UserAdapter)
when(UserAdapter_mock).get_user_company_rate_limit().\
thenReturn(get_fake_container_object())
self.test_obj = UserCompanyRateLimitValidation(self.user_public_key)
Here if you see I have mocked get_user_company_rate_limit() call from the testable function, container = self.adapter.get_user_company_rate_limit()
but I am still not able to figure out the way in which I can mock this call,
self.adapter = UserAdapter(user_public_key)
It is quite simple if you know the trick.
Creating an object in Python is very much like a function call to the class object. UserCompanyRateLimitValidation is 'invoking' UserAdapter(user_public_key). You want to stub the return value of that 'call' to return UserAdapter_mock.
You can stub this like you would stub a function in a module. The line you're missing is:
when(module_declaring_UserAdapter)\
.UserAdapter(self.user_public_key)\
.thenReturn(UserAdapter_mock)
After that, calling module_declaring_UserAdapter.UserAdapter(self.user_public_key) will return UserAdapter_mock.
Here's the link to the section in the manual: https://code.google.com/p/mockito-python/wiki/Stubbing#Modules
You have to be careful to choose the right module_declaring_UserAdapter, due to the way the from ... import ... statement works. From your code, I'd say you have to pick the module in which UserCompanyRateLimitValidation is declared.
Here is another way of looking at it. Say I have this code in which I would like to mock MyClass:
from some.module import MyClass
class AnotherClass:
def __init__(self):
self.my_class = MyClass()
One would typically call the imports as shown above. With some slight modification of the import, we can get it into a state where MyClass it can be mocked using mockito:
from some import module
class AnotherClass:
def __init__(self):
self.my_class = module.MyClass()
Then the mocking would work like so:
from some import module
when(module).MyClass().thenReturn(mock())
My title is fairly descriptive, but here goes.
Suppose I have this setup.
class BaseClass(object):
def __init__(self):
pass
def base_function(self, param="Hello World"):
print param
#multiple inheritance probably irrelevant but my problem deals with it
class DerivedClass(BaseClass, AnotherBaseClass):
def __init__(self):
pass
def advanced_function(self):
#blah blah blah
#code code code
self.base_function()
Now, I have a situation where I am testing a derived class, but in doing so, I need to ensure that it's base class methods are called. I tried doing something like this
from mock import MagicMock
d = DerivedClass()
super(DerivedClass, d).base_function = MagicMock()
d.advanced_function()
super(DerivedClass, d).base_function.assert_called()
I'm 100% sure this setup is wrong, because
AttributeError: 'super' object has no attribute 'base_function'
I know I'm doing something wrong with super, anyone have an idea?
Access via BaseClass.base_function. As you don't overload the method, you just inherit it, the DerivedClass.base_function is the same object:
id(BaseClass.base_function) == id(DerivedClass.base_function)
When the instances are created, they inherit the mock.
My test framework is currently based on a test-runner utility which itself is derived from the Eclipse pydev python test-runner. I'm switching to use Nose, which has many of the features of my custom test-runner but seems to be better quality code.
My test suite includes a number of abstract test-classes which previously never ran. The standard python testrunner (and my custom one) only ran instances of unittest.TestCase and unittest.TestSuite.
I've noticed that since I switched to Nose it's running just about anything which starts withthe name "test" which is annoying... because the naming convention we used for the test-mixins also looks like a test class to Nose. Previously these never ran as tests because they were not instances of TestCase or TestSuite.
Obviously I could re-name the methods to exclude the word "test" from their names... that would take a while because the test framework is very big and has a lot of inheritance. On the other hand it would be neat if there was a way to make Nose only see TestCases and TestSuites as being runnable... and nothing else.
Can this be done?
You could try to play with -m option for nosetests. From documentation:
A test class is a class defined in a
test module that matches testMatch or
is a subclass of unittest.TestCase
-m sets that testMatch, this way you can disable testing anything starting with test.
Another thing is that you can add __test__ = False to your test case class declaration, to mark it “not a test”.
If you want a truly abstract test class, you could just inherit the abstract class from object, then inherit in the testcases later.
For example:
class AbstractTestcases(object):
def test_my_function_does_something(self):
self.assertEquals("bar", self.func())
And then use it with:
class TestMyFooFunc(AbstractTestcases, unittest.TestCase):
def setUp(self):
self.func = lambda: "foo"
Then nosetests will pick up only the testcases in TestMyFooFunc and not those in AbstractTestCases.
You could use nose's --attr argument to specify an attribute posessed by the unittest.TestCase. For instance, I use:
nosetests --attr="assertAlmostEqual"
You could get even more careful by using and and or matching:
nosetests -A "assertAlmostEqual or addTest"
See unittest's documentation for a full list of methods/attributes, and Nose's description of the capabilities of the --attr plugin.
One addendum to #nailxx 's answer:
You could set __test__ = False in the parent class and then use a metaclass (see This question with some brilliant explanations) to set it back to True when subclassing.
(Finally, I found an excuse to use a metaclass!)
Although __test__ is a double underscore attribute, we have to explicitly set it to True, since not setting it would cause python just to lookup the attribute further up the MRO and evaluate it to False.
Thus, we need to check at class instantiation whether one of the parent classes has __test__ = False. If this is the case and the current class definition has not set __test__ itself, we shall add '__test__': True to the attributes dict.
The resulting code looks like this:
class TestWhenSubclassedMeta(type):
"""Metaclass that sets `__test__` back to `True` when subclassed.
Usage:
>>> class GenericTestCase(TestCase, metaclass=TestWhenSubclassed):
... __test__ = False
...
... def test_something(self):
... self.fail("This test is executed in a subclass, only.")
...
...
>>> class SpecificTestCase(GenericTestCase):
... pass
"""
def __new__(mcs, name, bases, attrs):
ATTR_NAME = '__test__'
VALUE_TO_RESET = False
RESET_VALUE = True
values = [getattr(base, ATTR_NAME) for base in bases
if hasattr(base, ATTR_NAME)]
# only reset if the first attribute is `VALUE_TO_RESET`
try:
first_value = values[0]
except IndexError:
pass
else:
if first_value == VALUE_TO_RESET and ATTR_NAME not in attrs:
attrs[ATTR_NAME] = RESET_VALUE
return super().__new__(mcs, name, bases, attrs)
One could extend this to some more implicit behaviour like “if the name starts with Abstract, set __test__ = False automatically”, but I for myself would keep the explicit assignment for clarity.
Let me paste simple unittests to demonstrate the behavior – and as a reminder that everybody should take the two minutes to test their code after introducing a feature.
from unittest import TestCase
from .base import TestWhenSubclassedMeta
class SubclassesTestCase(TestCase):
def test_subclass_resetted(self):
class Base(metaclass=TestWhenSubclassedMeta):
__test__ = False
class C(Base):
pass
self.assertTrue(C.__test__)
self.assertIn('__test__', C.__dict__)
def test_subclass_not_resetted(self):
class Base(metaclass=TestWhenSubclassedMeta):
__test__ = True
class C(Base):
pass
self.assertTrue(C.__test__)
self.assertNotIn('__test__', C.__dict__)
def test_subclass_attr_not_set(self):
class Base(metaclass=TestWhenSubclassedMeta):
pass
class C(Base):
pass
with self.assertRaises(AttributeError):
getattr(C, '__test__')
You can also use multiple inheritance on the test case level and let the base class inherit from object only. See this thread:
class MyBase(object):
def finishsetup(self):
self.z=self.x+self.y
def test1(self):
self.assertEqual(self.z, self.x+self.y)
def test2(self):
self.assert_(self.x > self.y)
class RealCase1(MyBase, unittest.TestCase):
def setUp(self):
self.x=10
self.y=5
MyBase.finishsetup(self)
class RealCase2(MyBase, unittest.TestCase):
def setUp(self):
self.x=42
self.y=13
MyBase.finishsetup(self)