Reputation: 8995
I am doing some unit testing and at some point I need to mock a super
call to throw an error, for example:
@classmethod
def myfunc(cls, *args, **kwargs)
try:
super(MyClass, cls).my_function(args, kwargs)
except MyException as e:
#...
I am using the mocker library to mock my objects in general but I haven't found a way to mock this.
Upvotes: 31
Views: 38546
Reputation: 2746
Python's own Mock class provides a spec
argument that should help with that:
with mock.patch('...ParentClass.myfunc') as mocked_fn:
mocked_fn.side_effect = MyException() # Parent's method will raise
instance = mock.Mock(spec=MyClass) # Enables using super()
MyClass.myfunc(instance) # Will enter your `except` block
Upvotes: 3
Reputation: 4789
Using unittest.mock
from the standard library I would do something like this.
In your class definition:
from somelib import ASuperClass
class MyClass(ASuperClass):
def my_cool_method(self):
return super().my_cool_method()
In the module where you are calling MyClass
:
from unittest.mock import patch
from mymodule import MyClass
@patch("mypackage.mymodule.ASuperClass.my_cool_method")
def call_with_mock(mocked_super):
myinstance = MyClass()
myinstance.my_cool_method()
# do stuff with `mocked_super`
call_with_mock()
Upvotes: 66
Reputation: 358
In case anyone needs another way to solve this mock:
# some_package/some_module.py
class MyClass(SuperClass):
def some_function(self):
result_super_call = super().function()
# test_file.py
@patch('some_package.some_module.super')
def test_something(self, mock_super):
obj = MyClass()
mock_super().some_function.return_value = None
Using Python 3.6
Upvotes: 7
Reputation: 1099
@Markus is looking in the right place. So long as you're unit testing (i.e. there's only one call to super
), you can mock __builtin__.super
as in:
with mock.patch('__builtin__.super') as mock_super:
mock_super.side_effect = TypeError
with self.assertRaises(TypeError):
obj.call_with_super()
Upvotes: 1
Reputation: 8995
I found a way, sort of hacky but it works, I'll explain with my example, this is based on this response so thanks @kindall:
def my_test(self):
import __builtin__
from mocker import Mocker, KWARGS, ARGS
mymocker = mocker.mock()
mymocker.my_function(ARGS, KWARGS)
mocker.throw(MyException)
def mysuper(*args, **kwargs):
if args and issubclass(MyClass, args[0]):
return mymocker
return original_super(*args, **kwargs)
__builtin__.original_super = super
__builtin__.super = mysuper
with mocker:
MyClass.myfunc()
so essentially what I do is check if the super
call is from the class I want to mock, else just do a normal super
.
Hope this helps someone :)
Upvotes: 7
Reputation: 8244
Well, then you need to mock the my_function
method of the superclass of MyClass
to blow up.
Upvotes: -1