SlideShare a Scribd company logo
1 of 32
Download to read offline
Python
Testing
using Mock
& PyTest
unittest.mock
unittest.mock
Defn: unittest.mock is a library for testing in Python. It
allows you to replace parts of your system under test with
mock objects and make assertions about how they have
been used.
• Using Mock you can replace/mock any dependency of
your code.
• Unreliable or expensive parts of code are mocked using
Mock, e.g. Networks, Intensive calculations, posting on
a website, system calls, etc.
• As a developer you want your calls to be right
rather than going all the way to final output.
• So to speed up your automated unit-tests you
need to keep out slow code from your test runs.
Mock - Basics
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m
<Mock id='140457934010912'>
>>> m.some_value = 23
>>> m.some_value
23
>>> m.other_value
<Mock name='mock.other_value' id='140457789462008'>
Mock Objects - Basics
>>> m.get_value(value=42)
<Mock name='mock.get_value()' id='140457789504816'>
>>> m.get_value.assert_called_once_with(value=42)
>>> m.get_value.assert_called_once_with(value=2)
raise AssertionError(_error_message()) from cause
AssertionError: Expected call: get_value(value=2)
Actual call: get_value(value=42)
• Flexible objects that can replace any part of
code.
• Creates attributes when accessed.
• Records how objects are being accessed.
• Using this history of object access you can make
assertions about objects.
More about Mock objects
>>> from unittest.mock import Mock
>>> config = {
... 'company': 'Lenovo',
... 'model': 'Ideapad Z510',
... 'get_sticker_count.return_value': 11,
... 'get_fan_speed.side_effect': ValueError
... }
>>> m = Mock(**config)
>>> m.company
'Lenovo'
>>> m.get_sticker_count()
11
>>> m.get_fan_speed()
raise effect
ValueError
Customize mock objects
Using spec to define attr
>>> user_info = ['first_name', 'last_name', 'email']
>>> m = Mock(spec=user_info)
>>> m.first_name
<Mock name='mock.first_name' id='140032117032552'>
>>> m.address
raise AttributeError("Mock object has no attribute %
r" % name)
AttributeError: Mock object has no attribute 'address'
Automatically create all specs
>>> from unittest.mock import create_autospec
>>> import os
>>> m = create_autospec(os)
>>> m.
Display all 325 possibilities? (y or n)
m.CLD_CONTINUED m.forkpty
m.CLD_DUMPED m.fpathconf
m.CLD_EXITED m.fsdecode
[CUT]
m.fchown m.walk
m.fdatasync m.write
m.fdopen m.writev
m.fork
Using Mock through patch
• Replaces a named object with Mock object
• Also can be used as decorator/context manager
that handles patching module and class level
attributes within the scope of a test.
1 # main.py
2 import requests
3 import json
4
5 def upload(text):
6 try:
7 url = 'http://paste.fedoraproject.org/'
8 data = {
9 'paste_data': text,
10 'paste_lang': None,
11 'api_submit': True,
12 'mode': 'json'
13 }
14 reply = requests.post(url, data=data)
15 return reply.json()
16 except ValueError as e:
17 print("Error:", e)
18 return None
19 except requests.exceptions.ConnectionError as e:
20 print('Error:', e)
21 return None
22 except KeyboardInterrupt:
23 print("Try again!!")
24 return None
25
26 if __name__ == '__main__':
27 print(upload('Now in boilerplate'))
1 # tests.py
2 import unittest
3 import requests
4 from unittest.mock import patch
5 from main import upload
6
7 text = 'This is ran from a test case'
8 url = 'http://paste.fedoraproject.org/'
9 data = {
10 'paste_data': text,
11 'paste_lang': None,
12 'api_submit': True,
13 'mode': 'json'
14 }
15 class TestUpload(unittest.TestCase):
16 def test_upload_function(self):
17 with patch('main.requests') as mock_requests:
18 result = upload(text) # call our function
19 mock_requests.post.assert_called_once_with(url, data=data)
20
21 def test_upload_ValueError(self):
22 with patch('main.requests') as mock_requests:
23 mock_requests.post.side_effect = ValueError
24 result = upload(text)
25 mock_requests.post.assert_any_call(url, data=data)
26 self.assertEqual(result, None)
patching methods #1
>>> @patch('requests.Response')
... @patch('requests.Session')
... def test(session, response):
... assert session is requests.Session
... assert response is requests.Response
...
>>> test()
patching methods #2
>>> with patch.object(os, 'listdir', return_value=
['abc.txt']) as mock_method:
... a = os.listdir('/home/hummer')
...
>>> mock_method.assert_called_once_with
('/home/hummer')
>>>
Mock return_value
>>> m = Mock()
>>> m.return_value = 'some random value 4'
>>> m()
'some random value 4'
OR
>>> m = Mock(return_value=3)
>>> m.return_value
3
>>> m()
3
Mock side_effect
• This can be a Exception, Iterable or function.
• If you pass in a function it will be called with
same arguments as the mock, unless function
returns DEFAULT singleton.
#1 side_effect for Exception
>>> m = Mock()
>>> m.side_effect = ValueError('You are always gonna get this!!')
>>> m()
raise effect
ValueError: You are always gonna get this!!
>>> m = Mock()
>>> m.side_effect = [1, 2, 3, 4]
>>> m(), m(), m(), m()
(1, 2, 3, 4)
>>> m()
StopIteration
#2 side_effect for returning
sequence of values
>>> m = Mock()
>>> side_effect = lambda value: value ** 3
>>> m.side_effect = side_effect
>>> m(2)
8
#3 side_effect as function
Installation
For Python3
$ pip3 install -U pytest
For Python2
$ pip install -U pytest
or
$ easy_install -U pytest
What is pytest?
● A fully featured Python Testing tool.
● Do automated tests.
Tests with less Boilerplate
1 import unittest
2
3 def cube(number):
4 return number ** 3
5
6
7 class Testing(unittest.TestCase):
8 def test_cube(self):
9 assert cube(2) == 8
Before py.test
1 def cube(number):
2 return number ** 3
3
4 def test_cube():
5 assert cube(2) == 8
6
7 # Here no imports or no classes are needed
After py.test
Running Tests
pytest will run all files in the current directory and
its subdirectories of the form test_*.py or
*_test.py or else you can always feed one file at a
time.
$ py.test cube.py
=============================== test session starts============================================
platform linux -- Python 3.4.3, pytest-2.8.3, py-1.4.30, pluggy-0.3.1
rootdir: /home/hummer/Study/Nov2015PythonPune/pyt, inifile:
collected 1 items
cube.py .
===============================1 passed in 0.01 seconds========================================
$ py.test
Run entire test suite
$ py.test test_bar.py
Run all tests in a specific file
$ py.test -k test_foo
Run all the tests that are named test_foo
By default pytest discovers tests in
test_*.py and *_test.py
pytest fixtures
• Fixtures are implemented in modular manner, as each
fixture triggers a function call which in turn can trigger
other fixtures.
• Fixtures scales from simple unit tests to complex
functional test.
• Fixtures can be reused across class, module or test
session scope.
1 import pytest
2
3 def needs_bar_teardown():
4 print('Inside "bar_teardown()"')
5
6 @pytest.fixture(scope='module')
7 def needs_bar(request):
8 print('Inside "needs bar()"')
9 request.addfinalizer(needs_bar_teardown)
10
11 def test_foo(needs_bar):
12 print('Inside "test_foo()"')
[hummer@localhost fixtures] $ py.test -sv fix.py
========================= test session starts ======================================
platform linux -- Python 3.4.3, pytest-2.8.3, py-1.4.30, pluggy-0.3.1 --
/usr/bin/python3
cachedir: .cache
rootdir: /home/hummer/Study/Nov2015PythonPune/pyt/fixtures, inifile:
collected 1 items
fix.py::test_foo Inside "needs bar()"
Inside "test_foo()"
PASSEDInside "bar_teardown()"
========================= 1 passed in 0.00 seconds==================================
[hummer@localhost fixtures] $
References
• http://www.toptal.com/python/an-introduction-
to-mocking-in-python
• https://docs.python.org/dev/library/unittest.
mock.html
• http://pytest.org/latest/contents.html
• http://pythontesting.net/

More Related Content

What's hot

Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
Richard Paul
 

What's hot (20)

Unit Testing in Java
Unit Testing in JavaUnit Testing in Java
Unit Testing in Java
 
Test ng
Test ngTest ng
Test ng
 
Core java
Core javaCore java
Core java
 
Testing Ansible
Testing AnsibleTesting Ansible
Testing Ansible
 
TestNG Framework
TestNG Framework TestNG Framework
TestNG Framework
 
Spring Framework - Spring Security
Spring Framework - Spring SecuritySpring Framework - Spring Security
Spring Framework - Spring Security
 
05 junit
05 junit05 junit
05 junit
 
Static Code Analysis
Static Code AnalysisStatic Code Analysis
Static Code Analysis
 
Unit Test
Unit TestUnit Test
Unit Test
 
Unit Testing in Python
Unit Testing in PythonUnit Testing in Python
Unit Testing in Python
 
Test Complete
Test CompleteTest Complete
Test Complete
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API
 
Modern Python Testing
Modern Python TestingModern Python Testing
Modern Python Testing
 
Maven Introduction
Maven IntroductionMaven Introduction
Maven Introduction
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Testing In Django
Testing In DjangoTesting In Django
Testing In Django
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShell
 
(Fios#03) 4. 파워셸 포렌식 조사 기법
(Fios#03) 4. 파워셸 포렌식 조사 기법(Fios#03) 4. 파워셸 포렌식 조사 기법
(Fios#03) 4. 파워셸 포렌식 조사 기법
 
Java I/O
Java I/OJava I/O
Java I/O
 

Viewers also liked

Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
David Xie
 
Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...
Timo Stollenwerk
 

Viewers also liked (20)

TDD in Python With Pytest
TDD in Python With PytestTDD in Python With Pytest
TDD in Python With Pytest
 
Mocking in python
Mocking in pythonMocking in python
Mocking in python
 
TDD in Go with Ginkgo and Gomega
TDD in Go with Ginkgo and GomegaTDD in Go with Ginkgo and Gomega
TDD in Go with Ginkgo and Gomega
 
Учим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTestУчим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTest
 
All about unit testing using (power) mock
All about unit testing using (power) mockAll about unit testing using (power) mock
All about unit testing using (power) mock
 
AUTOMATED TESTING USING PYTHON (ATE)
AUTOMATED TESTING USING PYTHON (ATE)AUTOMATED TESTING USING PYTHON (ATE)
AUTOMATED TESTING USING PYTHON (ATE)
 
тесты с фикстурами
тесты с фикстурамитесты с фикстурами
тесты с фикстурами
 
涯出世做客家人(客)
涯出世做客家人(客)涯出世做客家人(客)
涯出世做客家人(客)
 
Test double patterns with Python
Test double patterns with PythonTest double patterns with Python
Test double patterns with Python
 
Mozilla Web QA - Evolution of our Python WebDriver framework
Mozilla Web QA - Evolution of our Python WebDriver frameworkMozilla Web QA - Evolution of our Python WebDriver framework
Mozilla Web QA - Evolution of our Python WebDriver framework
 
Python Testing Fundamentals
Python Testing FundamentalsPython Testing Fundamentals
Python Testing Fundamentals
 
Unit Testing with Python
Unit Testing with PythonUnit Testing with Python
Unit Testing with Python
 
Python Ireland Nov 2010 Talk: Unit Testing
Python Ireland Nov 2010 Talk: Unit TestingPython Ireland Nov 2010 Talk: Unit Testing
Python Ireland Nov 2010 Talk: Unit Testing
 
Pytest testmon - executing large test suites quickly
Pytest testmon - executing large test suites quicklyPytest testmon - executing large test suites quickly
Pytest testmon - executing large test suites quickly
 
Нескучное тестирование с pytest
Нескучное тестирование с pytestНескучное тестирование с pytest
Нескучное тестирование с pytest
 
Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
 
Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...
 
Python in Test automation
Python in Test automationPython in Test automation
Python in Test automation
 
Funcargs & other fun with pytest
Funcargs & other fun with pytestFuncargs & other fun with pytest
Funcargs & other fun with pytest
 
Socket Programming In Python
Socket Programming In PythonSocket Programming In Python
Socket Programming In Python
 

Similar to Python testing using mock and pytest

pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
Yeongseon Choe
 

Similar to Python testing using mock and pytest (20)

How to fake_properly
How to fake_properlyHow to fake_properly
How to fake_properly
 
Managing Mocks
Managing MocksManaging Mocks
Managing Mocks
 
Numerical tour in the Python eco-system: Python, NumPy, scikit-learn
Numerical tour in the Python eco-system: Python, NumPy, scikit-learnNumerical tour in the Python eco-system: Python, NumPy, scikit-learn
Numerical tour in the Python eco-system: Python, NumPy, scikit-learn
 
Python testing
Python  testingPython  testing
Python testing
 
Testing My Patience
Testing My PatienceTesting My Patience
Testing My Patience
 
Viktor Tsykunov: Azure Machine Learning Service
Viktor Tsykunov: Azure Machine Learning ServiceViktor Tsykunov: Azure Machine Learning Service
Viktor Tsykunov: Azure Machine Learning Service
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
Mock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk
Mock it right! A beginner’s guide to world of tests and mocks, Maciej PolańczykMock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk
Mock it right! A beginner’s guide to world of tests and mocks, Maciej Polańczyk
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
 
Celery
CeleryCelery
Celery
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Unsupervised Aspect Based Sentiment Analysis at Scale
Unsupervised Aspect Based Sentiment Analysis at ScaleUnsupervised Aspect Based Sentiment Analysis at Scale
Unsupervised Aspect Based Sentiment Analysis at Scale
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
 
Node.js System: The Landing
Node.js System: The LandingNode.js System: The Landing
Node.js System: The Landing
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
Celery with python
Celery with pythonCelery with python
Celery with python
 
Pemrograman Python untuk Pemula
Pemrograman Python untuk PemulaPemrograman Python untuk Pemula
Pemrograman Python untuk Pemula
 
Automation with Ansible and Containers
Automation with Ansible and ContainersAutomation with Ansible and Containers
Automation with Ansible and Containers
 
Python mocking intro
Python mocking introPython mocking intro
Python mocking intro
 

More from Suraj Deshmukh

More from Suraj Deshmukh (13)

Building Container Defence Executable at a Time.pdf
Building Container Defence Executable at a Time.pdfBuilding Container Defence Executable at a Time.pdf
Building Container Defence Executable at a Time.pdf
 
Kubernetes psp and beyond
Kubernetes psp and beyondKubernetes psp and beyond
Kubernetes psp and beyond
 
Hardening Kubernetes by Securing Pods
Hardening Kubernetes by Securing PodsHardening Kubernetes by Securing Pods
Hardening Kubernetes by Securing Pods
 
Kubernetes Security Updates from Kubecon 2018 Seattle
Kubernetes Security Updates from Kubecon 2018 SeattleKubernetes Security Updates from Kubecon 2018 Seattle
Kubernetes Security Updates from Kubecon 2018 Seattle
 
Making kubernetes simple for developers
Making kubernetes simple for developersMaking kubernetes simple for developers
Making kubernetes simple for developers
 
Microservices on Kubernetes - The simple way
Microservices on Kubernetes - The simple wayMicroservices on Kubernetes - The simple way
Microservices on Kubernetes - The simple way
 
Kubernetes on CRI-O
Kubernetes on CRI-OKubernetes on CRI-O
Kubernetes on CRI-O
 
Taking containers from development to production
Taking containers from development to productionTaking containers from development to production
Taking containers from development to production
 
JSONSchema with golang
JSONSchema with golangJSONSchema with golang
JSONSchema with golang
 
What's new in kubernetes 1.3?
What's new in kubernetes 1.3?What's new in kubernetes 1.3?
What's new in kubernetes 1.3?
 
OpenShift meetup Bangalore
OpenShift meetup BangaloreOpenShift meetup Bangalore
OpenShift meetup Bangalore
 
macvlan and ipvlan
macvlan and ipvlanmacvlan and ipvlan
macvlan and ipvlan
 
Henge
HengeHenge
Henge
 

Recently uploaded

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Recently uploaded (20)

WSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital BusinessesWSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital Businesses
 
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next IntegrationWSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AIWSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AI
 
WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
WSO2CON 2024 - Not Just Microservices: Rightsize Your Services!
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public AdministrationWSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2Con2024 - Unleashing the Financial Potential of 13 Million People
WSO2Con2024 - Unleashing the Financial Potential of 13 Million PeopleWSO2Con2024 - Unleashing the Financial Potential of 13 Million People
WSO2Con2024 - Unleashing the Financial Potential of 13 Million People
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
WSO2CON 2024 - IoT Needs CIAM: The Importance of Centralized IAM in a Growing...
 
WSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration ToolingWSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration Tooling
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
 
WSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - KanchanaWSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - Kanchana
 
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public AdministrationWSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 

Python testing using mock and pytest

  • 3. unittest.mock Defn: unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. • Using Mock you can replace/mock any dependency of your code. • Unreliable or expensive parts of code are mocked using Mock, e.g. Networks, Intensive calculations, posting on a website, system calls, etc.
  • 4. • As a developer you want your calls to be right rather than going all the way to final output. • So to speed up your automated unit-tests you need to keep out slow code from your test runs.
  • 6. >>> from unittest.mock import Mock >>> m = Mock() >>> m <Mock id='140457934010912'> >>> m.some_value = 23 >>> m.some_value 23 >>> m.other_value <Mock name='mock.other_value' id='140457789462008'> Mock Objects - Basics
  • 7. >>> m.get_value(value=42) <Mock name='mock.get_value()' id='140457789504816'> >>> m.get_value.assert_called_once_with(value=42) >>> m.get_value.assert_called_once_with(value=2) raise AssertionError(_error_message()) from cause AssertionError: Expected call: get_value(value=2) Actual call: get_value(value=42)
  • 8. • Flexible objects that can replace any part of code. • Creates attributes when accessed. • Records how objects are being accessed. • Using this history of object access you can make assertions about objects. More about Mock objects
  • 9. >>> from unittest.mock import Mock >>> config = { ... 'company': 'Lenovo', ... 'model': 'Ideapad Z510', ... 'get_sticker_count.return_value': 11, ... 'get_fan_speed.side_effect': ValueError ... } >>> m = Mock(**config) >>> m.company 'Lenovo' >>> m.get_sticker_count() 11 >>> m.get_fan_speed() raise effect ValueError Customize mock objects
  • 10. Using spec to define attr >>> user_info = ['first_name', 'last_name', 'email'] >>> m = Mock(spec=user_info) >>> m.first_name <Mock name='mock.first_name' id='140032117032552'> >>> m.address raise AttributeError("Mock object has no attribute % r" % name) AttributeError: Mock object has no attribute 'address'
  • 11. Automatically create all specs >>> from unittest.mock import create_autospec >>> import os >>> m = create_autospec(os) >>> m. Display all 325 possibilities? (y or n) m.CLD_CONTINUED m.forkpty m.CLD_DUMPED m.fpathconf m.CLD_EXITED m.fsdecode [CUT] m.fchown m.walk m.fdatasync m.write m.fdopen m.writev m.fork
  • 12. Using Mock through patch • Replaces a named object with Mock object • Also can be used as decorator/context manager that handles patching module and class level attributes within the scope of a test.
  • 13. 1 # main.py 2 import requests 3 import json 4 5 def upload(text): 6 try: 7 url = 'http://paste.fedoraproject.org/' 8 data = { 9 'paste_data': text, 10 'paste_lang': None, 11 'api_submit': True, 12 'mode': 'json' 13 } 14 reply = requests.post(url, data=data) 15 return reply.json() 16 except ValueError as e: 17 print("Error:", e) 18 return None 19 except requests.exceptions.ConnectionError as e: 20 print('Error:', e) 21 return None 22 except KeyboardInterrupt: 23 print("Try again!!") 24 return None 25 26 if __name__ == '__main__': 27 print(upload('Now in boilerplate'))
  • 14. 1 # tests.py 2 import unittest 3 import requests 4 from unittest.mock import patch 5 from main import upload 6 7 text = 'This is ran from a test case' 8 url = 'http://paste.fedoraproject.org/' 9 data = { 10 'paste_data': text, 11 'paste_lang': None, 12 'api_submit': True, 13 'mode': 'json' 14 } 15 class TestUpload(unittest.TestCase): 16 def test_upload_function(self): 17 with patch('main.requests') as mock_requests: 18 result = upload(text) # call our function 19 mock_requests.post.assert_called_once_with(url, data=data) 20 21 def test_upload_ValueError(self): 22 with patch('main.requests') as mock_requests: 23 mock_requests.post.side_effect = ValueError 24 result = upload(text) 25 mock_requests.post.assert_any_call(url, data=data) 26 self.assertEqual(result, None)
  • 15. patching methods #1 >>> @patch('requests.Response') ... @patch('requests.Session') ... def test(session, response): ... assert session is requests.Session ... assert response is requests.Response ... >>> test()
  • 16. patching methods #2 >>> with patch.object(os, 'listdir', return_value= ['abc.txt']) as mock_method: ... a = os.listdir('/home/hummer') ... >>> mock_method.assert_called_once_with ('/home/hummer') >>>
  • 17. Mock return_value >>> m = Mock() >>> m.return_value = 'some random value 4' >>> m() 'some random value 4' OR >>> m = Mock(return_value=3) >>> m.return_value 3 >>> m() 3
  • 18. Mock side_effect • This can be a Exception, Iterable or function. • If you pass in a function it will be called with same arguments as the mock, unless function returns DEFAULT singleton.
  • 19. #1 side_effect for Exception >>> m = Mock() >>> m.side_effect = ValueError('You are always gonna get this!!') >>> m() raise effect ValueError: You are always gonna get this!!
  • 20. >>> m = Mock() >>> m.side_effect = [1, 2, 3, 4] >>> m(), m(), m(), m() (1, 2, 3, 4) >>> m() StopIteration #2 side_effect for returning sequence of values
  • 21. >>> m = Mock() >>> side_effect = lambda value: value ** 3 >>> m.side_effect = side_effect >>> m(2) 8 #3 side_effect as function
  • 22.
  • 23. Installation For Python3 $ pip3 install -U pytest For Python2 $ pip install -U pytest or $ easy_install -U pytest
  • 24. What is pytest? ● A fully featured Python Testing tool. ● Do automated tests.
  • 25. Tests with less Boilerplate 1 import unittest 2 3 def cube(number): 4 return number ** 3 5 6 7 class Testing(unittest.TestCase): 8 def test_cube(self): 9 assert cube(2) == 8 Before py.test
  • 26. 1 def cube(number): 2 return number ** 3 3 4 def test_cube(): 5 assert cube(2) == 8 6 7 # Here no imports or no classes are needed After py.test
  • 27. Running Tests pytest will run all files in the current directory and its subdirectories of the form test_*.py or *_test.py or else you can always feed one file at a time. $ py.test cube.py =============================== test session starts============================================ platform linux -- Python 3.4.3, pytest-2.8.3, py-1.4.30, pluggy-0.3.1 rootdir: /home/hummer/Study/Nov2015PythonPune/pyt, inifile: collected 1 items cube.py . ===============================1 passed in 0.01 seconds========================================
  • 28. $ py.test Run entire test suite $ py.test test_bar.py Run all tests in a specific file $ py.test -k test_foo Run all the tests that are named test_foo By default pytest discovers tests in test_*.py and *_test.py
  • 29. pytest fixtures • Fixtures are implemented in modular manner, as each fixture triggers a function call which in turn can trigger other fixtures. • Fixtures scales from simple unit tests to complex functional test. • Fixtures can be reused across class, module or test session scope.
  • 30. 1 import pytest 2 3 def needs_bar_teardown(): 4 print('Inside "bar_teardown()"') 5 6 @pytest.fixture(scope='module') 7 def needs_bar(request): 8 print('Inside "needs bar()"') 9 request.addfinalizer(needs_bar_teardown) 10 11 def test_foo(needs_bar): 12 print('Inside "test_foo()"')
  • 31. [hummer@localhost fixtures] $ py.test -sv fix.py ========================= test session starts ====================================== platform linux -- Python 3.4.3, pytest-2.8.3, py-1.4.30, pluggy-0.3.1 -- /usr/bin/python3 cachedir: .cache rootdir: /home/hummer/Study/Nov2015PythonPune/pyt/fixtures, inifile: collected 1 items fix.py::test_foo Inside "needs bar()" Inside "test_foo()" PASSEDInside "bar_teardown()" ========================= 1 passed in 0.00 seconds================================== [hummer@localhost fixtures] $