Testing.. 1, 2, 3!

Unit-testing in python.

Hi guys, this time around, it’s all about unit-testing with python3 and django using the standard django.test and unittest.mock libraries.

I’ve done my share of research and found no resources good enough over the internet other than the python docs. unittest.mock.patch is the preferential way of mocking methods and objects.

About patch , patch.object , patch.multiple and patch.dict , they all are essentially the same and are specific to the needs. We could use them interchangeably based on the instance reference.

For eg. the underlying methods are essentially the same and the former is preferrable when the SomeClass class is being reused elsewhere in the module.

from SomeModule import SomeClass
from unittest.mock import MagicMock, patch

@patch.object(SomeClass, 'some_method')
def test_random_thing(mocked_stuff):
...
mocked_stuff.assert_called_with(blah_blah)

@patch('SomeModule.SomeClass.some_method')
def test_random_thing_again(mocked_stuff):
...
mocked_stuff.assert_called_with(blah_blah)

Hereinafter, everyone faces the problem with chained function calls like google_drive().create_file('hello world.txt’).open(). Mocking them feels difficult. But this could be done in a simple way by using return_value.

class RandomClass:
def randomize():
results = set()
...
return results

@patch.object(RandomClass, 'randomize')
def test_change_label(self, mocked_labels, *args):
mocked_labels.return_value.add = MagicMock()
...
mocked_labels().add.assert_called_with('3.14159265359')

Mocking properties with PropertyMock:

We use properties within classes every now and then. Using the @property decorator which might feel like a pain in the arse sometimes. But, trust me it gets all easy with unittest.mock.PropertyMock. It helps wrap a property object within a PropertyMock object that makes life easy as it has it’s own __set__ and __get__ attributes. Setting property could be specced with assert_called_with() and getting it could be specced by the mocked property instance itself.

class Knight(StarWarsFighter):
...

@property  
def jedi(self):  
    return self.\_jedi

@jedi.setter  
def jedi(self, value):  
    self.\_jedi = value  

@patch.object(Knight, 'jedi', new_callable=PropertyMock,
return_value=False)
def test_jedi_property(self, mocked_jedi_property):
java = Knight()
if not java.jedi:
java.jedi = True
mocked_jedi.assert_called_with(True)

We could take this to the next level and analyze the call order with mocked_method.mock_calls which returns an list specifying the calls in their order of calls.