Documentos de Académico
Documentos de Profesional
Documentos de Cultura
MO CK
or not to
MO CK
that is th e question
To
MO CK
or not to
MO CK
that is th e question
a treatise narrated by
ANA BALICA
@anabalica
Thou
shalt
write
tests.
William Shakespeare
Chapter one
Mocks simulate
the looks and behaviour
of real objects
fig.1
fig.2
REAL
MO CK
mocks != stubs
Stubs
Mocks
Setup
Setup
Test
Setup expectations
Verify state
Test
Teardown
Verify expectations
Verify state
Teardown
unittest.mock
mock
# Python 3.3
# Python 2.x
Mock()
M o ck
>>> from mock import Mock
>>> m = Mock()
>>> m.foo = 1
>>> m.foo
1
>>> m.bar
<Mock name='mock.bar' id='4310136016'>
Mock()
MagicMock()
__lt__
__str__
__gt__
__int__
__len__
__hash__
__iter__
__exit__
__bool__
__sizeof__
Mock()
MagicMock()
patch()
Pat ching
from mock import patch
with patch('rainbow.Pony') as MockPony:
MockPony.return_value = 42
Pat ching
'rainbow.Pony'
# creatures.py
# rainbow.py
class Pony:
pass
Chapter two
Go o d
mo ck s
System calls
os.environ
with patch.dict('os.environ', {'ANDROID_ARGUMENT': ''}):
pf = Platform()
self.assertTrue(pf == android')
Streams
sys.stdout
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_print_live_refs_empty(self, stdout):
trackref.print_live_refs()
self.assertEqual(stdout.getvalue(),
'Live References\n\n\n')
Networking
request.urlopen
@patch('django.utils.six.moves.urllib.request.urlopen')
def test_oembed_photo_request(self, urlopen):
urlopen.return_value = self.dummy_response
result = wagtail_oembed("http://www.youtube.com/watch/")
self.assertEqual(result['type'], 'photo')
IO operations
json.loads
@patch.object(DataLoader, '_get_file_contents')
def test_parse_json_from_file(self, mock_def):
mock_def.return_value = ('{"a": 1, "b": 2, "c": 3}', True)
output = self._loader.load_from_file('dummy_json.txt')
self.assertEqual(output, dict(a=1, b=2, c=3))
Unpredictable results
random.random
with mock.patch('random.random', return_value=0.0):
with self.assertChanges(get_timeline_size, before=10, after=5):
backend.add(timeline, next(self.records))
System calls
Streams
Networking
IO operations
Clocks, time,
timezones
Unpredictable
results
Save time
Chapter three
Bad
mo ck s
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertTrue(saved_pony.age, 3)
mock_save.assert_called_once()
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertTrue(saved_pony.age, 3)
mock_save.assert_called_once()
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
mock_save.assert_called_once()
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
mock_save.assert_called_once()
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
mock_save.assert_called_twice()
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
mock_save.make_me_sandwich()
\_( )_/
Solution 1
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
mock_save.assert_called_once_with()
Solution 2
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
self.assertEqual(mock_save.call_count, 1)
Failure
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
self.assertEqual(mock_save.sandwich_count, 1)
Solution 3
Test Driven
Development
Problems?
with patch.object(Pony, 'save_base') as mock_save:
form = PonyForm(instance=pony, data=data)
self.assertTrue(form.is_valid())
saved_pony = form.save()
self.assertEqual(saved_pony.age, 3)
self.assertEqual(mock_save.call_count, 1)
Tests
pass?
SHIP IT!
Mayb e
its incomple te?
Integration tests
c = Client()
response = c.post('/pony/', {'age': 1})
self.assertEqual(response.status_code, 201)
Unit tests
Integration
tests
Mocks
Building on
Third-Party
Code
Application
objects
Adapter
layer
3rd party
API
Mock this
Application
objects
Test
this
cluster
Adapter
layer
3rd party
API
Conclusions
Mo ck s
can be
dange ro u s
The end