SlideShare una empresa de Scribd logo
1 de 39
Descargar para leer sin conexión
Mock it right! A beginner’s guide to world
of tests and mocks.
Maciej Polańczyk
maciej.polanczyk@stxnext.pl
Mock, Patch
Schedule
- Class to be tested
- Basic test
- Mock
- Not the best mock
- The best mock - spec_set
- Good mock - spec
- Mock requests.post
- Patch
- Patch.object
- Patch & import
- Patch - raise Exception
- Patch - different return_value
- Patch - method instead of return_value
- Patch - nesting patches
- Patch - TestCase
- Patch - in setUp
- Patch - environment variables
https://docs.python.org/3/library/unittest.mock.html
Class to be tested
import requests
class MessageSender:
_max_attempts = 3
def send(self, message):
data = {
'from': message.sender,
'to': message.receiver,
'subject': message.subject,
}
for attempt in range(self._max_attempts):
response = requests.post(url='http://example.com/email', data=data)
if response.status_code == requests.codes.created:
return True
return False
Basic test
from message_sender import MessageSender
class MessageSenderTests(unittest.TestCase):
def test_should_send_message():
# GIVEN
message_sender = MessageSender()
message_to_be_sent = self._get_mocked_message()
# WHEN
result = message_sender.send(message_to_be_sent)
# THEN
self.assertTrue(result)
# assert correct arguments were passed to request.post
Mock
Use mock when you can pass it
Mock - creation
from unittest.mock import Mock
# mock and attributes
mock = Mock()
print(mock.not_existing_field)
<Mock name='mock.not_existing_field' id='4327526528'>
from unittest.mock import Mock
# mock and methods
mock = Mock()
print(mock.not_existing_method())
<Mock name='mock.not_existing_method()' id='4372615856'>
Mock - creation
from unittest.mock import Mock
# mock and attributes
mock = Mock()
mock.existing_field = 5
print(mock.existing_field)
5
from unittest.mock import Mock
# mock and methods
mock = Mock()
mock.existing_method.return_value = 5
print(mock.existing_method())
5
Mock - creation
from unittest.mock import Mock
# mock and attributes
mock = Mock(existing_field=5)
print(mock.existing_field)
5
from unittest.mock import Mock
# mock and methods
mock = Mock(existing_method=Mock(return_value=5))
print(mock.existing_method())
5
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock.existing_method()
# in test method:
mock.existing_method.assert_called_once_with()
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock.existing_method(1)
# in test method:
mock.existing_method.assert_called_once_with(1)
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock.existing_method(1)
mock.existing_method(2)
# in test method:
mock.existing_method.assert_any_call(1)
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock(3)
mock.existing_method(1)
mock.existing_method(2)
print(mock.call_args_list)
output from print: [call(3)]
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock(3)
mock.existing_method(1)
mock.existing_method(2)
print(mock.method_calls)
output from print: [call.existing_method(1), call.existing_method(2)]
Mock - assertions
from unittest.mock import Mock
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock(3)
mock.existing_method(1)
mock.existing_method(2)
print(mock.mock_calls)
output from print: [call(3), call.existing_method(1), call.existing_method(2)]
Mock - assertions
from unittest.mock import Mock, call
# in test method:
mock = Mock()
mock.existing_method.return_value = 5
# in source code:
mock(3)
mock.existing_method(1)
mock.existing_method(2)
# in test method:
self.assertEqual(mock.mock_calls, [call(3), call.existing_method(1), call.existing_method(2)])
self.assertEqual(mock.existing_method.mock_calls, [call(1), call(2)])
Not the best mock
from unittest.mock import Mock
@staticmethod
def _get_mocked_message():
message_mock = Mock(
receiver='maciej.polanczyk@stxnext.pl',
sender='maciej.polanczyk@test.com',
subject='testing sending message'
)
return message_mock
The best mock - spec_set
from unittest.mock import Mock
from message import Message
@staticmethod
def _get_mocked_message():
message_mock = Mock(
spec_set=Message,
receiver='maciej.polanczyk@stxnext.pl',
sender='maciej.polanczyk@test.com',
subject='testing sending message'
)
return message_mock
Message class
class Message:
receiver = None
sender = None
subject = None
Message class
def Message:
def __init__(self, receiver, sender, subject):
self.receiver = receiver
self.sender = sender
self.subject = subject
Good mock - spec
import requests
from unittest.mock import Mock
@staticmethod
def _get_success_response():
response_mock = Mock(
spec=requests.Response,
status_code=requests.codes.created
)
return response_mock
Good mock - spec
import requests
from unittest.mock import Mock
@staticmethod
def _get_failure_response():
response_mock = Mock(
spec=requests.Response,
status_code=requests.codes.bad
)
return response_mock
Basic test
from message_sender import MessageSender
class MessageSenderTests(unittest.TestCase):
def test_should_send_message():
# GIVEN
message_sender = MessageSender()
message_to_be_sent = self._get_mocked_message()
# WHEN
result = message_sender.send(message_to_be_sent)
# THEN
self.assertTrue(result)
# assert correct arguments were passed to request.post
Mock request.post
import requests
class MessageSender:
_max_attempts = 3
def send(self, message):
data = {
'from': message.sender,
'to': message.receiver,
'subject': message.subject,
}
for attempt in range(self._max_attempts):
response = requests.post(url='http://example.com/email', data=data)
if response.status_code == requests.codes.created:
return True
return False
Mock request.post
class MessageSender:
_max_attempts = 3
def __init__():
self._sender = ...
def send(self, message):
...
response = self._sender.post(
url='http://example.com/email',
data=data,
)
...
class MessageSenderTests(unittest.TestCase):
def test_should_send_message(self):
# GIVEN
message_sender = MessageSender()
message_sender._sender = self._get_mocked_post_method()
...
@staticmethod
def _get_mocked_post_method():
post_method_mock = Mock(
# spec_set=SenderClass
return_value=MessageSenderTests._get_success_response()
)
return post_method_mock
Patch
Use patch when you can not pass mock
Patch
from unittest.mock import patch
from message_sender import MessageSender
@patch('requests.post', autospec=True)
def test_should_send_message(self, post_mock):
# GIVEN
post_mock.return_value = self._get_success_response()
...
# THEN
self.assertTrue(result)
post_mock.assert_called_once_with(
data={
'from': 'maciej.polanczyk@test.com',
...
},
url='http://example.com/email'
)
Patch.object
import requests
from unittest.mock import patch
from message_sender import MessageSender
@patch.object(requests, 'post', autospec=True)
def test_should_send_message(self, post_mock):
# GIVEN
post_mock.return_value = self._get_success_response()
...
# THEN
self.assertTrue(result)
post_mock.assert_called_once_with(
data={
...
},
url='http://example.com/email'
)
Patch & imports
from requests import post
...
def send(self, message):
...
response = post(
url='http://example.com/email',
data=data,
)
...
from unittest.mock import patch
import message_sender
from message_sender import MessageSender
@patch.object(message_sender, 'post', autospec=True)
def test_should_send_message(self, post_mock):
...
import requests
...
def send(self, message):
...
response = requests.post(
url='http://example.com/email',
data=data,
)
…
import requests
from unittest.mock import patch
from message_sender import MessageSender
@patch.object(requests, 'post', autospec=True)
def test_should_send_message(self, post_mock):
...
Patch - raise Exception
import requests
class MessageSender:
_max_attempts = 3
def send(self, message):
data = {
'from': message.sender,
'to': message.receiver,
'subject': message.subject,
}
for attempt in range(self._max_attempts):
response = requests.post(url='http://example.com/email', data=data)
if response.status_code == requests.codes.created:
return True
return False
Patch - raise Exception
@patch.object(requests, 'post')
def test_should_not_catch_exception(self, post_mock):
# GIVEN
post_mock.side_effect = RequestException(
'Expected exception from unit tests'
)
message_sender = MessageSender()
message_to_be_sent = self._get_example_message()
# WHEN & THEN
with self.assertRaisesRegex(RequestException, 'Expected exception'):
message_sender.send(message_to_be_sent)
post_mock.assert_called_once_with(
data={
...
},
url='http://example.com/email'
)
Patch - different
return_value
import requests
class MessageSender:
_max_attempts = 3
def send(self, message):
data = {
'from': message.sender,
'to': message.receiver,
'subject': message.subject,
}
for attempt in range(self._max_attempts):
response = requests.post(url='http://example.com/email', data=data)
if response.status_code == requests.codes.created:
return True
return False
Patch - different
return_value
@patch.object(requests, 'post', autospec=True)
def test_should_retry_sending_when_incorrect_status_received(self, post_mock):
# GIVEN
post_mock.side_effect = [self._get_failure_response(),
self._get_failure_response(),
self._get_failure_response(),]
message_to_be_sent = self._get_example_message()
message_sender = MessageSender()
# WHEN
result = message_sender.send(message_to_be_sent)
# THEN
self.assertFalse(result)
expected_calls = [self._get_expected_call(),
self._get_expected_call(),
self._get_expected_call(),]
self.assertEqual(post_mock.call_args_list, expected_calls)
def _get_expected_call(self):
return call(
data = {
'from': 'maciej.polanczyk@test.com',
'subject': 'testing sending message',
'to': 'maciej.polanczyk@stxnext.pl'
},
url = 'http://example.com/email'
)
Patch - method instead
of return_value
@patch.object(requests, 'post', autospec=True)
def test_should_send_message_tooo(self, post_mock):
# GIVEN
def implementation_from_unit_test(*args, **kwargs):
return self._get_success_response()
post_mock.side_effect = implementation_from_unit_test
...
Patch - nesting patches
@patch.object(requests, 'post', autospec=True)
@patch.object(requests, 'get', autospec=True)
@patch.object(requests, 'put', autospec=True)
def test_should_send_message_tooo(self, put_mock, get_mock, post_mock):
# GIVEN
...
# WHEN
...
# THEN
...
Patch - TestCase
class MessageSenderTests(unittest.TestCase):
@patch.object(requests, 'post', autospec=True)
def test_should_send_message(self, post_mock):
pass
@patch.object(requests, 'post', autospec=True)
def test_should_not_catch_exception(self, post_mock):
pass
@patch.object(requests, 'post', autospec=True)
class MessageSenderTests(unittest.TestCase):
def test_should_send_message(self, post_mock):
pass
def test_should_not_catch_exception(self, post_mock):
pass
Patch - in setUp
class MessageSenderTests(unittest.TestCase):
def setUp(self):
super().setUp()
patcher = patch('requests.post')
self.addCleanup(patcher.stop)
self._post_mock = patcher.start()
def test_should_send_message(self):
# GIVEN
self._post_mock.return_value = self._get_success_response()
# WHEN
...
# THEN
...
Patch - environment
variables
class MessageSenderTests(unittest.TestCase):
@patch.dict('os.environ', {'not_existing_key': 'some_value'}, clear=True)
def test_should_override_environment_variables(self):
self.assertEqual(os.environ, {'not_existing_key': 'some_value'})
Summary
Use mock when you can pass it
Use patch when you can not pass mock
Thank you!
Questions?

Más contenido relacionado

La actualidad más candente

Unit Testing Presentation
Unit Testing PresentationUnit Testing Presentation
Unit Testing Presentation
nicobn
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnit
varuntaliyan
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Enterprise PHP Center
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
dpc
 
Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
David Xie
 

La actualidad más candente (20)

Unit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnitUnit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnit
 
Unit Testing Presentation
Unit Testing PresentationUnit Testing Presentation
Unit Testing Presentation
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnit
 
Parametrized testing, v2
Parametrized testing, v2Parametrized testing, v2
Parametrized testing, v2
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to hero
 
Pytest: escreva menos, teste mais
Pytest: escreva menos, teste maisPytest: escreva menos, teste mais
Pytest: escreva menos, teste mais
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentation
 
Java programs
Java programsJava programs
Java programs
 
PhpUnit Best Practices
PhpUnit Best PracticesPhpUnit Best Practices
PhpUnit Best Practices
 
Unit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDDUnit testing with PHPUnit - there's life outside of TDD
Unit testing with PHPUnit - there's life outside of TDD
 
Test your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practiceTest your code like a pro - PHPUnit in practice
Test your code like a pro - PHPUnit in practice
 
Composing method
Composing methodComposing method
Composing method
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit Testing
 
Simulado java se 7 programmer
Simulado java se 7 programmerSimulado java se 7 programmer
Simulado java se 7 programmer
 
Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
 

Destacado

Destacado (6)

How to apply deep learning to 3 d objects
How to apply deep learning to 3 d objectsHow to apply deep learning to 3 d objects
How to apply deep learning to 3 d objects
 
EuroPython 2017 - How to make money with your Python open-source project
EuroPython 2017 - How to make money with your Python open-source projectEuroPython 2017 - How to make money with your Python open-source project
EuroPython 2017 - How to make money with your Python open-source project
 
Europy17_dibernardo
Europy17_dibernardoEuropy17_dibernardo
Europy17_dibernardo
 
Type Annotations in Python: Whats, Whys and Wows!
Type Annotations in Python: Whats, Whys and Wows!Type Annotations in Python: Whats, Whys and Wows!
Type Annotations in Python: Whats, Whys and Wows!
 
OpenAPI development with Python
OpenAPI development with PythonOpenAPI development with Python
OpenAPI development with Python
 
EuroPython 2017 - PyData - Deep Learning your Broadband Network @ HOME
EuroPython 2017 - PyData - Deep Learning your Broadband Network @ HOMEEuroPython 2017 - PyData - Deep Learning your Broadband Network @ HOME
EuroPython 2017 - PyData - Deep Learning your Broadband Network @ HOME
 

Similar a Mock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk

pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
Yeongseon Choe
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
mfrost503
 

Similar a Mock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk (20)

Auto testing!
Auto testing!Auto testing!
Auto testing!
 
Pruebas unitarias con django
Pruebas unitarias con djangoPruebas unitarias con django
Pruebas unitarias con django
 
Objective-c Runtime
Objective-c RuntimeObjective-c Runtime
Objective-c Runtime
 
Managing Mocks
Managing MocksManaging Mocks
Managing Mocks
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
How to fake_properly
How to fake_properlyHow to fake_properly
How to fake_properly
 
Spock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted VinkeSpock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted Vinke
 
Python programming : Inheritance and polymorphism
Python programming : Inheritance and polymorphismPython programming : Inheritance and polymorphism
Python programming : Inheritance and polymorphism
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Mutation Testing: Testing your tests
Mutation Testing: Testing your testsMutation Testing: Testing your tests
Mutation Testing: Testing your tests
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
PYTHON-Chapter 3-Classes and Object-oriented Programming: MAULIK BORSANIYA
PYTHON-Chapter 3-Classes and Object-oriented Programming: MAULIK BORSANIYAPYTHON-Chapter 3-Classes and Object-oriented Programming: MAULIK BORSANIYA
PYTHON-Chapter 3-Classes and Object-oriented Programming: MAULIK BORSANIYA
 
Django (Web Konferencia 2009)
Django (Web Konferencia 2009)Django (Web Konferencia 2009)
Django (Web Konferencia 2009)
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Unit testing
Unit testingUnit testing
Unit testing
 
Testers guide to unit testing
Testers guide to unit testingTesters guide to unit testing
Testers guide to unit testing
 
wk5ppt2_Iris
wk5ppt2_Iriswk5ppt2_Iris
wk5ppt2_Iris
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 

Más de Pôle Systematic Paris-Region

Más de Pôle Systematic Paris-Region (20)

OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...
 
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...
 
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...
 
OSIS19_Cloud : Performance and power management in virtualized data centers, ...
OSIS19_Cloud : Performance and power management in virtualized data centers, ...OSIS19_Cloud : Performance and power management in virtualized data centers, ...
OSIS19_Cloud : Performance and power management in virtualized data centers, ...
 
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...
 
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...
 
OSIS19_IoT : State of the art in security for embedded systems and IoT, by Pi...
OSIS19_IoT : State of the art in security for embedded systems and IoT, by Pi...OSIS19_IoT : State of the art in security for embedded systems and IoT, by Pi...
OSIS19_IoT : State of the art in security for embedded systems and IoT, by Pi...
 
Osis19_IoT: Proof of Pointer Programs with Ownership in SPARK, by Yannick Moy
Osis19_IoT: Proof of Pointer Programs with Ownership in SPARK, by Yannick MoyOsis19_IoT: Proof of Pointer Programs with Ownership in SPARK, by Yannick Moy
Osis19_IoT: Proof of Pointer Programs with Ownership in SPARK, by Yannick Moy
 
Osis18_Cloud : Pas de commun sans communauté ?
Osis18_Cloud : Pas de commun sans communauté ?Osis18_Cloud : Pas de commun sans communauté ?
Osis18_Cloud : Pas de commun sans communauté ?
 
Osis18_Cloud : Projet Wolphin
Osis18_Cloud : Projet Wolphin Osis18_Cloud : Projet Wolphin
Osis18_Cloud : Projet Wolphin
 
Osis18_Cloud : Virtualisation efficace d’architectures NUMA
Osis18_Cloud : Virtualisation efficace d’architectures NUMAOsis18_Cloud : Virtualisation efficace d’architectures NUMA
Osis18_Cloud : Virtualisation efficace d’architectures NUMA
 
Osis18_Cloud : DeepTorrent Stockage distribué perenne basé sur Bittorrent
Osis18_Cloud : DeepTorrent Stockage distribué perenne basé sur BittorrentOsis18_Cloud : DeepTorrent Stockage distribué perenne basé sur Bittorrent
Osis18_Cloud : DeepTorrent Stockage distribué perenne basé sur Bittorrent
 
Osis18_Cloud : Software-heritage
Osis18_Cloud : Software-heritageOsis18_Cloud : Software-heritage
Osis18_Cloud : Software-heritage
 
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
 
OSIS18_IoT: La securite des objets connectes a bas cout avec l'os et riot
OSIS18_IoT: La securite des objets connectes a bas cout avec l'os et riotOSIS18_IoT: La securite des objets connectes a bas cout avec l'os et riot
OSIS18_IoT: La securite des objets connectes a bas cout avec l'os et riot
 
OSIS18_IoT : Solution de mise au point pour les systemes embarques, par Julio...
OSIS18_IoT : Solution de mise au point pour les systemes embarques, par Julio...OSIS18_IoT : Solution de mise au point pour les systemes embarques, par Julio...
OSIS18_IoT : Solution de mise au point pour les systemes embarques, par Julio...
 
OSIS18_IoT : Securisation du reseau des objets connectes, par Nicolas LE SAUZ...
OSIS18_IoT : Securisation du reseau des objets connectes, par Nicolas LE SAUZ...OSIS18_IoT : Securisation du reseau des objets connectes, par Nicolas LE SAUZ...
OSIS18_IoT : Securisation du reseau des objets connectes, par Nicolas LE SAUZ...
 
OSIS18_IoT : Ada and SPARK - Defense in Depth for Safe Micro-controller Progr...
OSIS18_IoT : Ada and SPARK - Defense in Depth for Safe Micro-controller Progr...OSIS18_IoT : Ada and SPARK - Defense in Depth for Safe Micro-controller Progr...
OSIS18_IoT : Ada and SPARK - Defense in Depth for Safe Micro-controller Progr...
 
OSIS18_IoT : RTEMS pour l'IoT professionnel, par Pierre Ficheux (Smile ECS)
OSIS18_IoT : RTEMS pour l'IoT professionnel, par Pierre Ficheux (Smile ECS)OSIS18_IoT : RTEMS pour l'IoT professionnel, par Pierre Ficheux (Smile ECS)
OSIS18_IoT : RTEMS pour l'IoT professionnel, par Pierre Ficheux (Smile ECS)
 
PyParis 2017 / Un mooc python, by thierry parmentelat
PyParis 2017 / Un mooc python, by thierry parmentelatPyParis 2017 / Un mooc python, by thierry parmentelat
PyParis 2017 / Un mooc python, by thierry parmentelat
 

Último

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 

Mock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk

  • 1. Mock it right! A beginner’s guide to world of tests and mocks. Maciej Polańczyk maciej.polanczyk@stxnext.pl Mock, Patch
  • 2. Schedule - Class to be tested - Basic test - Mock - Not the best mock - The best mock - spec_set - Good mock - spec - Mock requests.post - Patch - Patch.object - Patch & import - Patch - raise Exception - Patch - different return_value - Patch - method instead of return_value - Patch - nesting patches - Patch - TestCase - Patch - in setUp - Patch - environment variables https://docs.python.org/3/library/unittest.mock.html
  • 3. Class to be tested import requests class MessageSender: _max_attempts = 3 def send(self, message): data = { 'from': message.sender, 'to': message.receiver, 'subject': message.subject, } for attempt in range(self._max_attempts): response = requests.post(url='http://example.com/email', data=data) if response.status_code == requests.codes.created: return True return False
  • 4. Basic test from message_sender import MessageSender class MessageSenderTests(unittest.TestCase): def test_should_send_message(): # GIVEN message_sender = MessageSender() message_to_be_sent = self._get_mocked_message() # WHEN result = message_sender.send(message_to_be_sent) # THEN self.assertTrue(result) # assert correct arguments were passed to request.post
  • 5. Mock Use mock when you can pass it
  • 6. Mock - creation from unittest.mock import Mock # mock and attributes mock = Mock() print(mock.not_existing_field) <Mock name='mock.not_existing_field' id='4327526528'> from unittest.mock import Mock # mock and methods mock = Mock() print(mock.not_existing_method()) <Mock name='mock.not_existing_method()' id='4372615856'>
  • 7. Mock - creation from unittest.mock import Mock # mock and attributes mock = Mock() mock.existing_field = 5 print(mock.existing_field) 5 from unittest.mock import Mock # mock and methods mock = Mock() mock.existing_method.return_value = 5 print(mock.existing_method()) 5
  • 8. Mock - creation from unittest.mock import Mock # mock and attributes mock = Mock(existing_field=5) print(mock.existing_field) 5 from unittest.mock import Mock # mock and methods mock = Mock(existing_method=Mock(return_value=5)) print(mock.existing_method()) 5
  • 9. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock.existing_method() # in test method: mock.existing_method.assert_called_once_with()
  • 10. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock.existing_method(1) # in test method: mock.existing_method.assert_called_once_with(1)
  • 11. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock.existing_method(1) mock.existing_method(2) # in test method: mock.existing_method.assert_any_call(1)
  • 12. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock(3) mock.existing_method(1) mock.existing_method(2) print(mock.call_args_list) output from print: [call(3)]
  • 13. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock(3) mock.existing_method(1) mock.existing_method(2) print(mock.method_calls) output from print: [call.existing_method(1), call.existing_method(2)]
  • 14. Mock - assertions from unittest.mock import Mock # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock(3) mock.existing_method(1) mock.existing_method(2) print(mock.mock_calls) output from print: [call(3), call.existing_method(1), call.existing_method(2)]
  • 15. Mock - assertions from unittest.mock import Mock, call # in test method: mock = Mock() mock.existing_method.return_value = 5 # in source code: mock(3) mock.existing_method(1) mock.existing_method(2) # in test method: self.assertEqual(mock.mock_calls, [call(3), call.existing_method(1), call.existing_method(2)]) self.assertEqual(mock.existing_method.mock_calls, [call(1), call(2)])
  • 16. Not the best mock from unittest.mock import Mock @staticmethod def _get_mocked_message(): message_mock = Mock( receiver='maciej.polanczyk@stxnext.pl', sender='maciej.polanczyk@test.com', subject='testing sending message' ) return message_mock
  • 17. The best mock - spec_set from unittest.mock import Mock from message import Message @staticmethod def _get_mocked_message(): message_mock = Mock( spec_set=Message, receiver='maciej.polanczyk@stxnext.pl', sender='maciej.polanczyk@test.com', subject='testing sending message' ) return message_mock
  • 18. Message class class Message: receiver = None sender = None subject = None
  • 19. Message class def Message: def __init__(self, receiver, sender, subject): self.receiver = receiver self.sender = sender self.subject = subject
  • 20. Good mock - spec import requests from unittest.mock import Mock @staticmethod def _get_success_response(): response_mock = Mock( spec=requests.Response, status_code=requests.codes.created ) return response_mock
  • 21. Good mock - spec import requests from unittest.mock import Mock @staticmethod def _get_failure_response(): response_mock = Mock( spec=requests.Response, status_code=requests.codes.bad ) return response_mock
  • 22. Basic test from message_sender import MessageSender class MessageSenderTests(unittest.TestCase): def test_should_send_message(): # GIVEN message_sender = MessageSender() message_to_be_sent = self._get_mocked_message() # WHEN result = message_sender.send(message_to_be_sent) # THEN self.assertTrue(result) # assert correct arguments were passed to request.post
  • 23. Mock request.post import requests class MessageSender: _max_attempts = 3 def send(self, message): data = { 'from': message.sender, 'to': message.receiver, 'subject': message.subject, } for attempt in range(self._max_attempts): response = requests.post(url='http://example.com/email', data=data) if response.status_code == requests.codes.created: return True return False
  • 24. Mock request.post class MessageSender: _max_attempts = 3 def __init__(): self._sender = ... def send(self, message): ... response = self._sender.post( url='http://example.com/email', data=data, ) ... class MessageSenderTests(unittest.TestCase): def test_should_send_message(self): # GIVEN message_sender = MessageSender() message_sender._sender = self._get_mocked_post_method() ... @staticmethod def _get_mocked_post_method(): post_method_mock = Mock( # spec_set=SenderClass return_value=MessageSenderTests._get_success_response() ) return post_method_mock
  • 25. Patch Use patch when you can not pass mock
  • 26. Patch from unittest.mock import patch from message_sender import MessageSender @patch('requests.post', autospec=True) def test_should_send_message(self, post_mock): # GIVEN post_mock.return_value = self._get_success_response() ... # THEN self.assertTrue(result) post_mock.assert_called_once_with( data={ 'from': 'maciej.polanczyk@test.com', ... }, url='http://example.com/email' )
  • 27. Patch.object import requests from unittest.mock import patch from message_sender import MessageSender @patch.object(requests, 'post', autospec=True) def test_should_send_message(self, post_mock): # GIVEN post_mock.return_value = self._get_success_response() ... # THEN self.assertTrue(result) post_mock.assert_called_once_with( data={ ... }, url='http://example.com/email' )
  • 28. Patch & imports from requests import post ... def send(self, message): ... response = post( url='http://example.com/email', data=data, ) ... from unittest.mock import patch import message_sender from message_sender import MessageSender @patch.object(message_sender, 'post', autospec=True) def test_should_send_message(self, post_mock): ... import requests ... def send(self, message): ... response = requests.post( url='http://example.com/email', data=data, ) … import requests from unittest.mock import patch from message_sender import MessageSender @patch.object(requests, 'post', autospec=True) def test_should_send_message(self, post_mock): ...
  • 29. Patch - raise Exception import requests class MessageSender: _max_attempts = 3 def send(self, message): data = { 'from': message.sender, 'to': message.receiver, 'subject': message.subject, } for attempt in range(self._max_attempts): response = requests.post(url='http://example.com/email', data=data) if response.status_code == requests.codes.created: return True return False
  • 30. Patch - raise Exception @patch.object(requests, 'post') def test_should_not_catch_exception(self, post_mock): # GIVEN post_mock.side_effect = RequestException( 'Expected exception from unit tests' ) message_sender = MessageSender() message_to_be_sent = self._get_example_message() # WHEN & THEN with self.assertRaisesRegex(RequestException, 'Expected exception'): message_sender.send(message_to_be_sent) post_mock.assert_called_once_with( data={ ... }, url='http://example.com/email' )
  • 31. Patch - different return_value import requests class MessageSender: _max_attempts = 3 def send(self, message): data = { 'from': message.sender, 'to': message.receiver, 'subject': message.subject, } for attempt in range(self._max_attempts): response = requests.post(url='http://example.com/email', data=data) if response.status_code == requests.codes.created: return True return False
  • 32. Patch - different return_value @patch.object(requests, 'post', autospec=True) def test_should_retry_sending_when_incorrect_status_received(self, post_mock): # GIVEN post_mock.side_effect = [self._get_failure_response(), self._get_failure_response(), self._get_failure_response(),] message_to_be_sent = self._get_example_message() message_sender = MessageSender() # WHEN result = message_sender.send(message_to_be_sent) # THEN self.assertFalse(result) expected_calls = [self._get_expected_call(), self._get_expected_call(), self._get_expected_call(),] self.assertEqual(post_mock.call_args_list, expected_calls) def _get_expected_call(self): return call( data = { 'from': 'maciej.polanczyk@test.com', 'subject': 'testing sending message', 'to': 'maciej.polanczyk@stxnext.pl' }, url = 'http://example.com/email' )
  • 33. Patch - method instead of return_value @patch.object(requests, 'post', autospec=True) def test_should_send_message_tooo(self, post_mock): # GIVEN def implementation_from_unit_test(*args, **kwargs): return self._get_success_response() post_mock.side_effect = implementation_from_unit_test ...
  • 34. Patch - nesting patches @patch.object(requests, 'post', autospec=True) @patch.object(requests, 'get', autospec=True) @patch.object(requests, 'put', autospec=True) def test_should_send_message_tooo(self, put_mock, get_mock, post_mock): # GIVEN ... # WHEN ... # THEN ...
  • 35. Patch - TestCase class MessageSenderTests(unittest.TestCase): @patch.object(requests, 'post', autospec=True) def test_should_send_message(self, post_mock): pass @patch.object(requests, 'post', autospec=True) def test_should_not_catch_exception(self, post_mock): pass @patch.object(requests, 'post', autospec=True) class MessageSenderTests(unittest.TestCase): def test_should_send_message(self, post_mock): pass def test_should_not_catch_exception(self, post_mock): pass
  • 36. Patch - in setUp class MessageSenderTests(unittest.TestCase): def setUp(self): super().setUp() patcher = patch('requests.post') self.addCleanup(patcher.stop) self._post_mock = patcher.start() def test_should_send_message(self): # GIVEN self._post_mock.return_value = self._get_success_response() # WHEN ... # THEN ...
  • 37. Patch - environment variables class MessageSenderTests(unittest.TestCase): @patch.dict('os.environ', {'not_existing_key': 'some_value'}, clear=True) def test_should_override_environment_variables(self): self.assertEqual(os.environ, {'not_existing_key': 'some_value'})
  • 38. Summary Use mock when you can pass it Use patch when you can not pass mock