Mock superclass __init__ method or superclass in general for testing
I want to check out a Python class I have written that looks like this:
from external_library import GenericClass
class SpecificClass(GenericClass):
def __init__(self, a, b, c):
super(SpecificClass, self).__init__(a, b)
self.c = c
def specific_method(self, d):
self.initialize()
return d + self.c + self.b + self.a.fetch()
GenericClass
defined by external library ( external_library
):
class GenericClass(object):
def __init__(self, a, b):
self.a = a
self.b = b + "append"
def initialize(self):
# it might be an expensive operation
self.a.initialize()
def specific_method(self, d):
raise NotImplementedError
How to check specific_method
? Besides GenericClass.initialize
, should I make fun of GenericClass
in general GenericClass.__init__
, super
or GenericClass.a
and GenericClass.b
? Or is my approach to the problem completely wrong?
Please use it mock
as a mocking library and pytest
as a test environment. The solution must be Python2.6 + compatible.
Thanks in advance.
source to share
It's a bit tricky to guess the best approach from the synthetic example. Whenever possible, it is best to use only the required layouts and most possible real objects. But this is a compromise game, and when it is difficult to create a real object, and the dependencies are deep, and distorted layouts can be a very powerful tool. Plus, bullying gives you a variety of feeling points where your test can play. The fee is worth paying: sometimes with a breadboard, you can hide bugs that can only be raised with integration tests.
IMHO for your case, your best bet is to just mock a
and set the return value fetch
. You can also test the calla.initialize()
If your goal is just mock a.initialize()
(and off course a.fetch()
, which I think doesn't make sense without initialize()
); best is just patch
a
an object.
In any case, the last test is about fixing the superclass. In your case, it's a little difficult, and you have to pay __init__
to insert an attribute a
, b
. If you are worried about what GenericClass
to do in init, you have to patch it directly with the __init__
: patch method this class is useless because its reference is already in the definition SpecificClass
(it is resolved super
, not GenericClass.__init__(...)
>). Perhaps in real code you need to struggle with the read-only property for a
and b
: again, if you can use a real object and just fix as little method / object as possible, this is the best choice. I love the framework mock
, but in some cases this is not the best deal.
One more thing: I used patch.multiple
to have a more compact example, but fixing the method with two patch.object
does the same job.
import unittest
from mock import Mock, patch, DEFAULT, PropertyMock
from specific import SpecificClass
class A():
def initialize(self):
raise Exception("Too slow for tests!!!!")
def fetch(self):
return "INVALID"
class MyTestCase(unittest.TestCase):
def test_specific_method(self):
a = A()
with patch.multiple(a, initialize=DEFAULT, fetch=DEFAULT) as mocks:
mock_initialize, mock_fetch = mocks["initialize"], mocks["fetch"]
mock_fetch.return_value = "a"
sc = SpecificClass(a, "b", "c")
self.assertEqual("dcbappenda", sc.specific_method("d"))
mock_initialize.assert_called_with()
def test_sanity_check(self):
a = A()
sc = SpecificClass(a, "b", "c")
self.assertRaises(Exception, sc.specific_method, "d")
#You can patch it in your module if it is imported by from .. as ..
@patch("specific.GenericClass.__init__", autospec=True, return_value=None)
def test_super_class(self, mock_init):
sc = SpecificClass("a", "b", "c")
mock_init.assert_called_with(sc, "a", "b")
#Inject a and b
sc.a = Mock()
sc.b = "b"
#configure a
sc.a.fetch.return_value = "a"
self.assertEqual("dcba", sc.specific_method("d"))
sc.a.initialize.assert_called_with()
source to share