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.