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.
Slide 4
Slide 4 text
• 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.
Slide 5
Slide 5 text
Mock - Basics
Slide 6
Slide 6 text
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m
>>> m.some_value = 23
>>> m.some_value
23
>>> m.other_value
Mock Objects - Basics
Slide 7
Slide 7 text
>>> m.get_value(value=42)
>>> 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)
Slide 8
Slide 8 text
• 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
Using spec to define attr
>>> user_info = ['first_name', 'last_name', 'email']
>>> m = Mock(spec=user_info)
>>> m.first_name
>>> m.address
raise AttributeError("Mock object has no attribute %
r" % name)
AttributeError: Mock object has no attribute 'address'
Slide 11
Slide 11 text
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
Slide 12
Slide 12 text
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.
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')
>>>
Slide 17
Slide 17 text
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
Slide 18
Slide 18 text
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.
Slide 19
Slide 19 text
#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!!
Slide 20
Slide 20 text
>>> 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
Slide 21
Slide 21 text
>>> m = Mock()
>>> side_effect = lambda value: value ** 3
>>> m.side_effect = side_effect
>>> m(2)
8
#3 side_effect as function
Slide 22
Slide 22 text
No content
Slide 23
Slide 23 text
Installation
For Python3
$ pip3 install -U pytest
For Python2
$ pip install -U pytest
or
$ easy_install -U pytest
Slide 24
Slide 24 text
What is pytest?
●
A fully featured Python Testing tool.
●
Do automated tests.
Slide 25
Slide 25 text
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
Slide 26
Slide 26 text
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
Slide 27
Slide 27 text
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========================================
Slide 28
Slide 28 text
$ 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
Slide 29
Slide 29 text
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.