The document provides a comprehensive guide to using the unittest.mock library in Python for testing, emphasizing the creation of mock objects to replace real components in tests. It covers basic mock operations, patching methods, and the integration with pytest for automated testing, including examples and error handling. Additionally, it explains the use of fixtures in pytest, showcasing their scalability and reusability across different test scopes.
unittest.mock
Defn: unittest.mock isa 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 adeveloper 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.
>>> from unittest.mockimport 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 objectsthat 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 todefine 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 allspecs
>>> 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 throughpatch
• 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')
>>>
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
• Thiscan 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 forException
>>> 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
What is pytest?
●A fully featured Python Testing tool.
● Do automated tests.
25.
Tests with lessBoilerplate
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):
2return 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 willrun 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 entiretest 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
• Fixturesare 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.