SlideShare a Scribd company logo
1 of 33
Python mocking intro
IoC, DIP, DI and IoC containers
Mock Objects
• In Object-Oriented programming mock objects are defined as
simulated objects
 They mimic the behavior of real objects in controlled ways
• The whole point of unit testing is isolating certain functionality (unit)
and test just that. We are trying to remove all other dependencies
 Sometimes this can be a database, networking or a file system, so using
mock object we don’t step into the world of integration tests
 Other times dependency can be just some other class or function
• A mock object should be used in the situations when
 The real object is slow
 The real object rarely occurs and is difficult to produce artificially
 The real object produces non-deterministic results
 The real object does not yet exist (which often is the case in TDD)
Some external dependencies
• External resources are a common source of non-unit test dependencies
– Registry and environment variables
– Network connections and databases
– Files and directories
– Current date and time
– Hardware devices
– And so on…
• External dependencies can often be replaced by test doubles or pre-
evaluated objects
– Test Double (think stunt double) is a generic term for any case where you replace
a production object for testing purposes
– Pre-evaluated objects can be already fetched/computed records in memory arrays
Some various test doubles
• Dummy objects are passed around but never actually used. Usually they are
just used to fill parameter lists
• Fake objects actually have working implementations, but usually take some
shortcut which makes them not suitable for production (an In-Memory Test
Database is a good example)
• Stubs provide canned answers to calls made during the test, usually not
responding at all to anything outside what's programmed in for the test
• Spies are stubs that also record some information based on how they were
called. One form of this might be an email service that records how many
messages it has sent
• Mocks are pre-programmed with expectations which form a specification of
the calls they are expected to receive. They can throw an exception if they
receive a call they don't expect and are checked during verification to ensure
they got all the calls they were expecting
Source: https://martinfowler.com/bliki/TestDouble.html
Test doubles and unittest.mock
• Mocking and related techniques may be easier in Python than in many other
languages
• Dependencies can be substituted without changing class design
• The unittest.mock library provides a core Mock class removing the need to
create a host of stubs throughout your test suite
• After performing an action, you can make assertions about which attributes
and methods were used and arguments they were called with
• You can also specify return values and set needed attributes in the normal
way
• Additionally, mock provides a patch() decorator that handles patching
module and class level attributes within the scope of a test for creating
unique objects
• Mock is relatively easy to use and is designed for use with unittest
• https://docs.python.org/3/library/unittest.mock.html
unittest.mock Quick Guide – return_value and side_effect
from unittest.mock import Mock # import the Mock class
from unittest.mock import MagicMock # import the MagicMock class
class ProductionClass():
def __init__(self):
pass
# Mock and MagicMock objects create all attributes and methods as you access them and store details
# of how they have been used. You can configure them, to specify return values or limit what
# attributes are available, and then make assertions about how they have been used
thing = ProductionClass()
thing.method = MagicMock(return_value = 3) # calling method() will return 3
print(thing.method()) # print the return_value
thing.method(3, 4, 5, key = 'value')
thing.method.assert_called_with(3, 4, 5, key ='value') # AssertionError if different than expected call
print(dir(Mock())) # show all the default mock methods / attributes
# side_effect allows you to perform side effects, including raising an exception when a mock is called
my_mock = Mock(side_effect = KeyError('foo')) # create a new mock object with KeyError exception
# my_mock() # mock -> side_effect = KeyError exception
values = {'a': 1, 'b': 2, 'c': 3}
def side_effect_func(arg):
return values[arg]
my_mock.side_effect = side_effect_func # mock -> side_effect_func
print(my_mock('a'), my_mock('b'), my_mock('c')) # print values side_effect_func(arg)
my_mock.side_effect = [5, 4, 3, 2, 1] # change side_effect again
for x in range(0, 5): # side_effect now returns array one by one
print(my_mock())
quick_guide_mock1.py # output
thing.method(): 3
dir(Mock()):
['assert_any_call',
'assert_called',
'assert_called_once',
'assert_called_once_with',
'assert_called_with',
'assert_has_calls',
'assert_not_called',
'attach_mock', 'call_args',
'call_args_list', 'call_count',
'called', 'configure_mock',
'method_calls', 'mock_add_spec',
'mock_calls', 'reset_mock',
'return_value', 'side_effect']
dict:
1 2 3
range:
5
4
3
2
1
The Mock / MagicMock classes and patch
• Mock is a flexible mock object intended to replace the use of stubs and other test
doubles throughout your code
• Mocks are callable and create attributes as new mocks when you access them.
Accessing the same attribute will always return the same mock
• Mocks record how you use them, allowing you to make assertions about what your
code has done to them
• MagicMock is a subclass of Mock with all the magic methods (__init__, __str__,
__new__, __main__, __name__, ...) pre-created and ready to use
 https://docs.python.org/3/library/unittest.mock.html#magicmock-and-magic-method-support
 https://rszalski.github.io/magicmethods/
 You can use MagicMock without having to configure the magic methods yourself
 The constructor parameters have the same meaning as for Mock
• The patch() decorators makes it easy to temporarily
replace classes in a particular module with a Mock object.
By default patch() will create a MagicMock for you
# patched classes are input
@patch('my_mod.ClsName')
def testFunc(MockCls):
# MockCls == my_mod.ClsName
assert MockCls is my_mod.ClsName
# call patched class or MockCls.Mthd()
my_mod.ClsName()
MockCls.Mthd = Mock(return_value = ...
Create a Mock object
Create a new Mock object. Mock takes several optional arguments that specify the behaviour of the Mock object:
• spec: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If
you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and
methods). Accessing any attribute not in this list will raise an AttributeError.
• If spec is an object (rather than a list of strings) then __class__ returns the class of the spec object. This allows mocks to pass
isinstance() tests.
• spec_set: A stricter variant of spec. If used, attempting to set or get an attribute on the mock that isn’t on the object passed as
spec_set will raise an AttributeError.
• side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or
dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT, the
return value of this function is used as the return value.
• Alternatively side_effect can be an exception class or instance. In this case the exception will be raised when the mock is called.
• If side_effect is an iterable then each call to the mock will return the next value from the iterable.
• A side_effect can be cleared by setting it to None.
• return_value: The value returned when the mock is called. By default this is a new Mock (created on first access). See the
return_value attribute.
• unsafe: By default if any attribute starts with assert or assret will raise an AttributeError. Passing unsafe=True will allow access to
these attributes.
• wraps: Item for the mock object to wrap. If wraps is not None then calling the Mock will pass the call through to the wrapped object
(returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the
wrapped object (so attempting to access an attribute that doesn’t exist will raise an AttributeError).
• If the mock has an explicit return_value set then calls are not passed to the wrapped object and the return_value is returned instead.
• name: If the mock has a name then it will be used in the repr of the mock. This can be useful for debugging. The name is propagated
to child mocks.
class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock
Mock class attributes 1
Mocks can also be called with arbitrary keyword arguments. These will be used to set attributes on the mock after it is created:
• assert_called(*args, **kwargs)
 Assert that the mock was called at least once.
• assert_called_once(*args, **kwargs)
 Assert that the mock was called exactly once.
• assert_called_with(*args, **kwargs)
 This method is a convenient way of asserting that calls are made in a particular way.
• assert_called_once_with(*args, **kwargs)
 Assert that the mock was called exactly once and that that call was with the specified arguments.
• assert_any_call(*args, **kwargs)
 Assert that the mock has been called with the specified arguments.
• assert_has_calls(calls, any_order=False)
 Assert that the mock has been called with the specified calls. The mock_calls list is checked for the calls..
• assert_not_called()
 Assert that the mock was never called.
• reset_mock(*, return_value=False, side_effect=False)
 The reset_mock method resets all the call attributes on a mock object.
• mock_add_spec(spec, spec_set=False)
 Add a spec. to a mock
• attach_mock(mock, attribute)
 Attach a mock as an attribute of this one, replacing its name and parent.
• configure_mock(**kwargs)
 Set attributes on the mock through keyword arguments.
# examples
mock_obj.assert_not_called()
mock_obj.assert_called_with(10)
Mock class attributes 2
• __dir__()
 Mock objects limit the results of dir(some_mock) to useful results
• _get_child_mock(**kw)
 Create the child mocks for attributes and return value
• called
 A boolean representing whether or not the mock object has been called
• call_count
 An integer telling you how many times the mock object has been called
• return_value
 Set this to configure the value returned by calling the mock
• side_effect
 This can either be a function to be called when the mock is called, an iterable or an exception (class or instance)
to be raised
• call_args
 This is either None (if the mock hasn’t been called), or the arguments that the mock was last called with
• call_args_list
 This is a list of all the calls made to the mock object in sequence
• method_calls
 As well as tracking calls to themselves, mocks also track calls to methods and attributes, and their methods and
attributes
• mock_calls
 mock_calls records all calls to the mock object, its methods, magic methods and return value mocks
• __class__
 Normally the __class__ attribute of an object will return its type. For a mock object with a spec, __class__ returns
the spec class instead
# examples
mock_obj.return_value = 10
mock_obj.side_effect = [1, 2, 3]
Using Mock objects
• Calling
 Mock objects are callable. The call will return the value set as the return_value attribute. The default
return value is a new Mock object; it is created the first time the return value is accessed (either
explicitly or by calling the Mock) - but it is stored and the same one returned each time
 https://docs.python.org/3/library/unittest.mock.html#calling
• Deleting attributes
 Mock objects create attributes on demand. This allows them to pretend to be objects of any type.
 You “block” attributes by deleting them. Once deleted, accessing an attribute will raise an
AttributeError
 https://docs.python.org/3/library/unittest.mock.html#deleting-attributes
• Mock names and the name attribute
 Since “name” is an argument to the Mock constructor, if you want your mock object to have a “name”
attribute you can’t just pass it in at creation time. There are two alternatives. One option is to use
configure_mock()
 https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute
• Attaching Mocks as Attributes
 When you attach a mock as an attribute of another mock (or as the return value) it becomes a “child”
of that mock. Calls to the child are recorded in the method_calls and mock_calls attributes of the
parent. This is useful for configuring child mocks and then attaching them to the parent, or for
attaching mocks to a parent that records all calls to the children and allows you to make assertions
about the order of calls between mocks
 https://docs.python.org/3/library/unittest.mock.html#attaching-mocks-as-attributes
del mock_obj.my_attr
Basic concepts unittest.mock – return_value
from unittest import mock # import the library
def print_answer():
print("42")
def print_number(num):
print(f"Number: {num}")
m1 = mock.Mock() # The main object that the library provides is Mock and you can instantiate it without any argument
print(dir(m1)) # show all the default mock methods / attributes
print(m1.some_attribute) # read a non-existent attribute
# Mock objects are callables, which means that they may act both as attributes and as methods. If you try to call
# the mock it just returns you another mock with a name that includes parentheses to signal its callable nature
print(m1.some_attribute())
# The simplest thing a mock can do for you is to return a given value every time you call it.
# This is configured setting the return_value attribute of a mock object
m1.some_attribute.return_value = 42
print(m1.some_attribute())
# Now the object does not return a mock object any more, instead it just returns the static value stored in the return_value attribute.
# Obviously you can also store a callable such as a function or an object,and the method will return it, but it will not run it.
m1.some_attribute.return_value = print_answer
print(m1.some_attribute())
# As you can see calling some_attribute() just returns the value stored in return_value, that is the function itself.
# To return values that come from a function we have to use a slightly more complex attribute of mock objects called side_effect.
gentle_intro_to_mock1.py
Basic concepts unittest.mock – side_effect 1
# The side_effect parameter of mock objects is a very powerful tool. It accepts 3 different flavours of objects, callables,
# iterables, and exceptions, and changes its behaviour accordingly. If you pass an exception the mock will raise it
m1.some_attribute.side_effect = ValueError('A custom value error')
try:
m1.some_attribute()
except BaseException as ex:
print(f"ValueError: {ex}")
# If you pass an iterable, such as for example a generator, or a plain list, tuple, or similar objects, the mock will
# yield the values of that iterable, i.e. return every value contained in the iterable on subsequent calls of the mock.
m1.some_attribute.side_effect = range(3)
print(m1.some_attribute())
print(m1.some_attribute())
print(m1.some_attribute())
# print(m1.some_attribute())
try:
print(m1.some_attribute())
except BaseException as ex:
print(f"StopIteration().value: {StopIteration().value}")
# As promised, the mock just returns every object found in the iterable (in this case a range object) once at a time
# until the generator is exhausted. According to the iterator protocol once every item has been returned
# the object raises the StopIteration exception, which means that you can correctly use it in a loop.
gentle_intro_to_mock1.py
Basic concepts unittest.mock – side_effect 2
# The last and perhaps most used case is that of passing a callable to side_effect, which shamelessly executes it with
# its own same parameters. This is very powerful, especially if you stop thinking about "functions" and start considering
# "callables". Indeed, side_effect also accepts a class and calls it, that is it can instantiate objects. Let us consider
# a simple example with a function without arguments
m1.some_attribute.side_effect = print_answer
m1.some_attribute()
# A slightly more complex example: a function with arguments
m1.some_attribute.side_effect = print_number
m1.some_attribute.side_effect(5)
# And finally an example with a class
m1.some_attribute.side_effect = Number
n1 = m1.some_attribute.side_effect(26)
n1.print_value()
# All the default mock methods / attributes
# ['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with',
# 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called',
# 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']
# From: http://www.thedigitalcatonline.com/blog/2016/03/06/python-mocks-a-gentle-introduction-part-1/
class Number(object):
def __init__(self, value):
self._value = value
def print_value(self):
print("Value:", self._value)
def print_answer():
print("42")
def print_number(num):
print(f"Number: {num}")
gentle_intro_to_mock1.py
Basic concepts unittest.mock - assert_called_with
• According to Sandi Metz (programmer and author) we need
to test only 3 types of messages (calls) between objects
 Incoming queries (assertion on result)
 Incoming commands (assertion on
direct public side effects)
 Outgoing commands (expectation on
call and arguments)
 https://www.sandimetz.com/
• What we usually are interested
in when dealing with an external
object is to know that a given
method has been called on it
• Python mocks provide the
assert_called_with() method
to check if a method has
been called on it
from unittest import mock
import unittest
import myobj
class TestMocking(unittest.TestCase):
def test_instantiation(self):
external_obj = mock.Mock()
myobj.MyObj(external_obj)
external_obj.connect.assert_called_with()
def test_setup(self):
external_obj = mock.Mock()
obj = myobj.MyObj(external_obj)
obj.setup()
external_obj.setup.assert_called_with(
cache=True, max_connections=256) # AssertionError
if __name__ == '__main__':
unittest.main()
class MyObj():
def __init__(self, repo):
self._repo = repo
repo.connect()
def setup(self):
self._repo.setup(cache=True)
test_gentle_intro_to_mock1.py
unittest.mock Mock class
• We check that the Hello.bar() method is called correct with ’HELLO’
• camelCase setUp() and tearDown() can perform initialization and cleanup of the test
fixture since they are called before and after the test
import unittest
from unittest.mock import Mock
class HelloTestTest(unittest.TestCase):
def setUp(self):
self.hello = Hello()
def tearDown(self):
pass
def test_foo(self):
msg = 'hello'
expected_bar_arg = 'HELLO'
self.hello.bar = Mock() # we mock the bar() method
self.hello.foo(msg)
# we check that bar was called with 'HELLO'
self.hello.bar.assert_called_once_with(expected_bar_arg)
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
class Hello(object):
def foo(self, msg):
MSG = msg.upper()
self.bar(MSG)
# the mocked bar() method
# def bar(self, MSG):
# print(MSG)
test_hellomock.py
unittest.mock MagicMock class
• MagicMock is a subclass of Mock with default implementations of most of the magic methods
• You can use MagicMock without having to configure the magic methods yourself
import unittest
from unittest.mock import MagicMock
from employee import Employee
class TestMocking(unittest.TestCase):
def test_mock1(self):
thing = Employee('Hans', 'Jones', 50)
# set return value
thing.method = MagicMock(return_value = 3)
# call the method
ret = thing.method(3, 4, 5, key='value')
print(f'ret: {ret}')
# check if we called correct
thing.method.assert_called_with(3, 4, 5, key='value')
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
test_mock.py
class Employee:
"""A sample Employee class"""
raise_amt = 1.05
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
The patchers
The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle
the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class
decorators.
• patch() acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the
target is patched with a new object. When the function/with statement exits the patch is undone.
• If new is omitted, then the target is replaced with a MagicMock. If patch() is used as a decorator and new is omitted, the created
mock is passed in as an extra argument to the decorated function. If patch() is used as a context manager the created mock is
returned by the context manager.
• target should be a string in the form 'package.module.ClassName'. The target is imported and the specified object replaced with
the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when
the decorated function is executed, not at decoration time.
• The spec and spec_set keyword arguments are passed to the MagicMock if patch is creating one for you.
• In addition you can pass spec=True or spec_set=True, which causes patch to pass in the object being mocked as the
spec/spec_set object.
• new_callable allows you to specify a different class, or callable object, that will be called to create the new object. By default
MagicMock is used.
• A more powerful form of spec is autospec. If you set autospec=True then the mock will be created with a spec from the object
being replaced. All attributes of the mock will also have the spec of the corresponding attribute of the object being replaced.
Methods and functions being mocked will have their arguments checked and will raise a TypeError if they are called with the
wrong signature. For mocks replacing a class, their return value (the ‘instance’) will have the same spec as the class. See the
create_autospec() function and Autospeccing.
• Instead of autospec=True you can pass autospec=some_object to use an arbitrary object as the spec instead of the one being
replaced.
unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch
patch.object, patch.dict and patch.multiple
• Patch the named member (attribute) on an object (target) with a mock object.
• patch.object() can be used as a decorator, class decorator or a context manager. Arguments new, spec, create,
spec_set, autospec and new_callable have the same meaning as for patch(). Like patch(), patch.object() takes
arbitrary keyword arguments for configuring the mock object it creates.
• When used as a class decorator patch.object() honours patch.TEST_PREFIX for choosing which methods to wrap.
• Patch a dictionary, or dictionary like object, and restore the dictionary to its original state after the test.
• in_dict can be a dictionary or a mapping like container. If it is a mapping then it must at least support getting, setting
and deleting items plus iterating over keys.
• in_dict can also be a string specifying the name of the dictionary, which will then be fetched by importing it.
• values can be a dictionary of values to set in the dictionary. values can also be an iterable of (key, value) pairs.
• Perform multiple patches in a single call. It takes the object to be patched (either as an object or a string to fetch the
object by importing) and keyword arguments for the patches
• Use DEFAULT as the value if you want patch.multiple() to create mocks for you. In this case the created mocks are
passed into a decorated function by keyword, and a dictionary is returned when patch.multiple() is used as a context
manager
patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch
patch.dict(in_dict, values=(), clear=False, **kwargs)
patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
unittest.mock patch() function
• patch() is the main mocking mechanism for the unittest.mock library
• patch() works by (temporarily) changing the object that a name points to with another one
• The basic principle is that you patch where an object is looked up, which is not necessarily the
same place as where it is defined
class TestMocking(unittest.TestCase):
# mocking MyMockedClass
def test_mock2(self):
# Patching a class replaces the class with a MagicMock instance
with patch('__main__.MyMockedClass') as MockClass:
# return_value of the mock will be used
instance = MockClass.return_value
instance.method.return_value = 'foo'
# assert MyMockedClass() is instance of MyMockedClass
self.assertIsInstance(instance, type(MyMockedClass()))
self.assertEqual(MyMockedClass().method(), 'foo')
self.assertEqual(instance.method(), 'foo')
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
import unittest
from unittest.mock import patch
class MyMockedClass:
def method(self):
pass
test_mock.py
unittest.mock Quick Guide – patch()
from unittest.mock import Mock # import the Mock class
from unittest.mock import MagicMock # import the MagicMock class
from unittest.mock import patch
import myobj
class ProductionClass():
def method(self, a, b, c):
pass
# The patch() decorator / context manager makes it easy to mock classes or objects in a module under test.
# The object you specify will be replaced with a mock (or other object) during the test and restored when the test ends
@patch('myobj.ClassName2')
@patch('myobj.ClassName1') # bottom-up passing of values
def test(MockClass1, MockClass2): # patched classes are input
myobj.ClassName1() # call patched class
myobj.ClassName2()
assert MockClass1 is myobj.ClassName1 # patched class is genuine
assert MockClass2 is myobj.ClassName2
assert MockClass1.called == True # patched class have been called
assert MockClass2.called == True
MockClass1.return_value = 'No AssertionError!'
return MockClass1.return_value
print(f'test(): {test()}') # printed values from test() comes from patched objects
# The patch.object()
with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
thing = ProductionClass()
thing.method(1, 2, 3)
print(mock_method.assert_called_once_with(1, 2, 3)) # patched class have been called once with (1, 2, 3) and retuns None
quick_guide_mock2.py
myobj.py
# The patch.dict()
foo = {'key': 'value'}
original = foo.copy()
with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
assert foo == {'newkey': 'newvalue'} # foo has new values
assert foo == original
# output
method_cs1
test(): No AssertionError!
mock_method.assert_called_once_with(1, 2, 3):
None
class ClassName1():
def __init__(self):
pass
class ClassName2():
def __init__(self):
pass
unittest.mock Quick Guide – autospec
# Mock supports the mocking of Python magic methods. The easiest way of using magic methods is with the MagicMock class. It allows you to do things like:
mock = MagicMock()
mock.__str__.return_value = 'foobarbaz' # return str(self)
print(str(mock)) # 'foobarbaz'
print(mock.__str__.assert_called_with()) # return str(self)
# Mock allows you to assign functions (or other Mock instances) to magic methods and they will be called appropriately.
# The MagicMock class is just a Mock variant that has all of the magic methods pre-created for you (well, all the useful ones anyway).
# The following is an example of using magic methods with the ordinary Mock class:
mock = Mock()
mock.__str__ = Mock(return_value='wheeeeee')
print(str(mock)) #'wheeeeee'
# note the () difference
mock.return_value = 'whoooooo'
print(str(mock())) #'whoooooo'
# For ensuring that the mock objects in your tests have the same api as the objects they are replacing, you can use auto-speccing.
# Auto-speccing can be done through the autospec argument to patch, or the create_autospec() function. Auto-speccing creates mock objects that have the
# same attributes and methods as the objects they are replacing, and any functions and methods
# (including constructors) have the same call signature as the real object.
# This ensures that your mocks will fail in the same way as your production code if they are used incorrectly:
from unittest.mock import create_autospec
def function(a, b, c):
pass
mock_function = create_autospec(function, return_value='fishy')
print(mock_function(1, 2, 3)) # 'fishy'
print(mock_function.assert_called_once_with(1, 2, 3))
#mock_function('wrong arguments') # TypeError: missing a required argument: 'b'
# create_autospec() can also be used on classes, where it copies the signature of the
# __init__ method, and on callable objects where it copies the signature of the __call__ method.
str(mock): foobarbaz
mock.__str__.assert_called_with(): None
str(mock): wheeeeee
str(mock()): whoooooo
mock_function(1, 2, 3): fishy
mock_function.assert_called_once_with(1, 2, 3): None
quick_guide_mock2.py
myobj.py
patch() and new_callable
• patch() away sys.std - we replace an object (sys.stdout) with an io.StringIO instance with the @patch
decorator
• patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None,
new_callable=None, **kwargs)
from io import StringIO
import unittest
from unittest.mock import patch
class MyMockedClass:
def foo_print(self):
print('Something that is not going to be printed to sys.stdout')
class TestMocking(unittest.TestCase):
@patch('sys.stdout', new_callable=StringIO)
def test_mock3(self, mock_stdout):
thing = MyMockedClass()
thing.foo_print()
# assert mock_stdout.getvalue() == 'Somethingn' # sys.stdout.getvalue()
self.assertEqual(mock_stdout.getvalue(), 'Something that is not going to be printed to sys.stdoutn')
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
test_mock.py
Basic concepts unittest.mock – patch 1
import unittest
from fileinfo import FileInfo
from unittest.mock import patch
from logger import Logger
class TestMocking(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.filename = 'somefile.ext'
def test_init_filename(self):
fi = FileInfo(self.filename)
self.assertEqual(fi.filename, self.filename)
def test_init_path(self):
relative_path = f'../{self.filename}'
fi = FileInfo(relative_path)
self.assertEqual(fi.filename, self.filename)
def test_get_info1(self):
original_path = f'../{self.filename}'
with patch('os.path.abspath') as abspath_mock: # patching os.path.abspath with patch()
test_abspath = 'some/abs/path'
abspath_mock.return_value = test_abspath # mocking os.path.abspath
fi = FileInfo(original_path)
retval = fi.get_info()
self.assertEqual(retval, (self.filename, original_path, test_abspath))
import os
class FileInfo:
def __init__(self, path):
self.original_path = path
self.filename = os.path.basename(path)
def get_info(self):
return self.filename, self.original_path,
os.path.abspath(self.filename)
def get_info_size(self):
return self.filename, self.original_path,
os.path.abspath(self.filename),
os.path.getsize(self.filename)
test_gentle_intro_to_mock2.py
Basic concepts unittest.mock – patch 2
@patch('os.path.abspath') # The patching decorator
def test_get_info2(self, abspath_mock):
original_path = f'../{self.filename}'
test_abspath = 'some/abs/path'
abspath_mock.return_value = test_abspath
fi = FileInfo(original_path)
self.assertEqual(fi.get_info(), (self.filename, original_path, test_abspath))
@patch('os.path.getsize') # Multiple patches
@patch('os.path.abspath') # bottom-up passing of values
def test_get_info3(self, abspath_mock, getsize_mock):
original_path = f'../{self.filename}'
test_abspath = 'some/abs/path'
abspath_mock.return_value = test_abspath
test_size = 1234
getsize_mock.return_value = test_size
fi = FileInfo(original_path)
self.assertEqual(fi.get_info_size(), (self.filename, original_path, test_abspath, test_size))
def test_get_info4(self):
original_path = f'../{self.filename}' # We can write the above test using two with statements as well
with patch('os.path.abspath') as abspath_mock:
test_abspath = 'some/abs/path'
abspath_mock.return_value = test_abspath
with patch('os.path.getsize') as getsize_mock:
test_size = 1234
getsize_mock.return_value = test_size
fi = FileInfo(original_path)
self.assertEqual(fi.get_info_size(), (self.filename, original_path, test_abspath, test_size))
test_gentle_intro_to_mock2.py
Basic concepts unittest.mock – patch 3
# Patching immutable objects == no change after creation
def test_init_logger(self):
lg = Logger()
self.assertEqual(lg.messages, [])
# @patch('datetime.datetime.now')
# def test_log1(self, mock_now):
# test_now = 123
# test_message = "A test message"
# mock_now.return_value = test_now
# lg = Logger()
# lg.log(test_message)
# self.assertEqual(lg.messages, [(test_now, test_message)])
@patch('logger.datetime.datetime')
def test_log2(self, mock_datetime):
test_now = 123
test_message = "A test message"
mock_datetime.now.return_value = test_now
lg = Logger()
lg.log(test_message)
self.assertEqual(lg.messages, [(test_now, test_message)])
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
import datetime
class Logger:
def __init__(self):
self.messages = []
def log(self, message):
self.messages.append((datetime.datetime.now(),
message))
test_get_info1 (__main__.TestMocking) ... ok
test_get_info2 (__main__.TestMocking) ... ok
test_get_info3 (__main__.TestMocking) ... ok
test_get_info4 (__main__.TestMocking) ... ok
test_init_filename (__main__.TestMocking) ... ok
test_init_logger (__main__.TestMocking) ... ok
test_init_path (__main__.TestMocking) ... ok
test_log2 (__main__.TestMocking) ... ok
test_gentle_intro_to_mock2.py
unittest.mock patch() a web request
• To get setup and teardown code that runs in a class before tests are
run we can have decorated class methods in camelCase
• To mock a web site request with patch() and
check URL call and returned result
from unittest.mock import patch
class TestEmployee(unittest.TestCase):
def test_monthly_schedule(self):
with patch('employee.requests.get') as mocked_get:
# set return values
mocked_get.return_value.ok = True
mocked_get.return_value.text = 'Success'
# perform a mock call with emp_1
schedule = self.emp_1.monthly_schedule('May')
mocked_get.assert_called_with('http://company.com/Schafer/May')
self.assertEqual(schedule, 'Success')
@classmethod
def setUpClass(cls):
print('setupClass')
@classmethod
def tearDownClass(cls):
print('teardownClass')
test_employee.py
Python unittest.mock example
import unittest
from unittest.mock import patch
from employee import Employee
class TestEmployee(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('setupClass')
@classmethod
def tearDownClass(cls):
print('teardownClass')
def setUp(self):
print('nsetUp')
self.emp_1 = Employee('Corey', 'Schafer', 50000)
self.emp_2 = Employee('Sue', 'Smith', 60000)
def tearDown(self):
print('tearDown')
#… additional code here removed for readability
def test_monthly_schedule(self):
with patch('employee.requests.get') as mocked_get:
mocked_get.return_value.ok = True
mocked_get.return_value.text = 'Success'
schedule = self.emp_1.monthly_schedule('May')
mocked_get.assert_called_with('http://company.com/Schafer/May')
self.assertEqual(schedule, 'Success')
mocked_get.return_value.ok = False
schedule = self.emp_2.monthly_schedule('June')
mocked_get.assert_called_with('http://company.com/Smith/June')
self.assertEqual(schedule, 'Bad Response!')
if __name__ == '__main__':
unittest.main(argv=['first-arg-is-ignored'], exit=False)
import requests
class Employee:
"""A sample Employee class"""
raise_amt = 1.05
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
@property
def email(self):
return 'f{self.first}.{self.last}@email.com'
@property
def fullname(self):
return 'f{self.first} {self.last}'
def apply_raise(self):
self.pay = int(self.pay * self.raise_amt)
#… additional code here removed for readability
def monthly_schedule(self, month):
response = requests.get(f'http://company.com/{self.last}/{month}')
if response.ok:
return response.text
else:
return 'Bad Response!'
----------- OUTPUT -----------
PS C:python_unittesting> python .test_employee.py -v
setupClass
test_apply_raise (__main__.TestEmployee) ...
setUp
test_apply_raise
tearDown
ok
test_email (__main__.TestEmployee) ...
setUp
test_email
tearDown
ok
test_fullname (__main__.TestEmployee) ...
setUp
test_fullname
tearDown
ok
test_monthly_schedule (__main__.TestEmployee) ...
setUp
tearDown
ok
teardownClass
------------------------------------------------------
Ran 4 tests in 0.007s
test_employee.py
and employee.py
IoC, DIP, DI and IoC containers
• IoC – Loose coupling between classes
• DIP – High-level modules should not
depend on low level modules. Both ...
• DI – A design pattern which implements the
IoC principle to invert the creation of
dependent objects
• IoC container – A framework used to
manage automatic dependency injection
https://www.tutorialsteacher.com/ioc/
Python and Dependency Injection 1
• Dependency Injection is a pattern that decreases coupling and increases
cohesion (forming a united whole) via the Dependency Inversion Principle
 The D in SOLID: https://en.wikipedia.org/wiki/Dependency_inversion_principle
• The DI design pattern implements the Inversion of Control (IoC) principle to
resolve dependencies: https://en.wikipedia.org/wiki/Dependency_injection
 If object A (a client) depends on object B (a service), object A must not create or
import object B directly - Instead object A must provide a way to inject object B
 The responsibilities of objects creation and dependency injection are usually
delegated to some external code - the dependency injector
• There are several ways to inject a service (B) into a client (A)
 by passing it (B) as an __init__ argument (constructor / initializer injection)
 by setting it (B) as an attribute’s value (attribute injection)
 by passing it (B) as a method’s argument (method injection)
di_python.py
di_python_factory.py
vehicle.py
Python and Dependency Injection 2
• The dependency injection pattern has a few strict rules that should be
followed
 The client (A) delegates to the dependency injector the responsibility of injecting its
dependencies - the services (B)
 The client should not know how to create the service, it should only know the interface of the
service
 The service should not know about that it is used by the client
 The dependency injector knows how to create the client and the service
 It also knows that the client depends on the service, and knows how to inject the service into the
client
 The client and service should know nothing about the dependency injector
• Python Dependency Dependency Injector
 https://github.com/ets-labs/python-dependency-injector
• Python IoC Container
 https://github.com/eyaldror/di_container
di_python.py
di_python_factory.py
vehicle.py
Dependency Injection (Dis)Advantages
• Advantages
 Control of application structure
 Decreased coupling of application components
 Increased code reusability
 Increased testability
 Increased maintainability
 Reconfiguration of a system without rebuilding
• Disadvantages
 One need to explicitly specify the dependencies
 Some extra work in the beginning
Recommended viewing and reading
• Python Mocks: a gentle introduction - Part 1 and 2
 http://www.thedigitalcatonline.com/blog/2016/03/06/python-mocks-a-gentle-introduction-part-1/
• Python 3.x unittest.mock documentation
 https://docs.python.org/3/library/unittest.mock.html
• What the mock? - A cheatsheet for mocking in Python
 https://medium.com/@yeraydiazdiaz/what-the-mock-cheatsheet-mocking-in-python-
6a71db997832
 https://github.com/yeraydiazdiaz/wtmock
• Test Driven Development (TDD) with Python – Mock Objects
 https://rubikscode.net/2019/03/11/test-driven-development-tdd-with-python-mock-objects/
• Python Tutorial: Unit Testing Your Code with the unittest Module
 https://www.youtube.com/watch?v=6tNS--WetLI
• Demystifying the Patch Function
 https://www.youtube.com/watch?v=ww1UsGZV8fQ

More Related Content

Similar to Python mocking intro

Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummiesFraboni Ec
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummiesJames Wong
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMockYing Zhang
 
CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!Ortus Solutions, Corp
 
Devday2016 real unittestingwithmockframework-phatvu
Devday2016 real unittestingwithmockframework-phatvuDevday2016 real unittestingwithmockframework-phatvu
Devday2016 real unittestingwithmockframework-phatvuPhat VU
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
Testing – With Mock Objects
Testing – With Mock ObjectsTesting – With Mock Objects
Testing – With Mock Objectsemmettwalsh
 
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...DevDay.org
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Dror Helper
 
Integration and Unit Testing in Java using Test Doubles like mocks and stubs
Integration and Unit Testing in Java using Test Doubles like mocks and stubsIntegration and Unit Testing in Java using Test Doubles like mocks and stubs
Integration and Unit Testing in Java using Test Doubles like mocks and stubsRody Middelkoop
 
Junit, mockito, etc
Junit, mockito, etcJunit, mockito, etc
Junit, mockito, etcYaron Karni
 

Similar to Python mocking intro (20)

Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 
Unit Testing
Unit TestingUnit Testing
Unit Testing
 
Spock
SpockSpock
Spock
 
How to fake_properly
How to fake_properlyHow to fake_properly
How to fake_properly
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMock
 
CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!
 
Devday2016 real unittestingwithmockframework-phatvu
Devday2016 real unittestingwithmockframework-phatvuDevday2016 real unittestingwithmockframework-phatvu
Devday2016 real unittestingwithmockframework-phatvu
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Testing – With Mock Objects
Testing – With Mock ObjectsTesting – With Mock Objects
Testing – With Mock Objects
 
Unit testing
Unit testingUnit testing
Unit testing
 
Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...
[DevDay 2016] Real Unit Testing with mocking framework - Speaker: Phat Vu – S...
 
Easy mock
Easy mockEasy mock
Easy mock
 
Unit tests and TDD
Unit tests and TDDUnit tests and TDD
Unit tests and TDD
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 
Integration and Unit Testing in Java using Test Doubles like mocks and stubs
Integration and Unit Testing in Java using Test Doubles like mocks and stubsIntegration and Unit Testing in Java using Test Doubles like mocks and stubs
Integration and Unit Testing in Java using Test Doubles like mocks and stubs
 
Junit, mockito, etc
Junit, mockito, etcJunit, mockito, etc
Junit, mockito, etc
 
EasyMock for Java
EasyMock for JavaEasyMock for Java
EasyMock for Java
 

Recently uploaded

Introduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsIntroduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsTechSoup
 
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...fonyou31
 
Disha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdfDisha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdfchloefrazer622
 
The byproduct of sericulture in different industries.pptx
The byproduct of sericulture in different industries.pptxThe byproduct of sericulture in different industries.pptx
The byproduct of sericulture in different industries.pptxShobhayan Kirtania
 
social pharmacy d-pharm 1st year by Pragati K. Mahajan
social pharmacy d-pharm 1st year by Pragati K. Mahajansocial pharmacy d-pharm 1st year by Pragati K. Mahajan
social pharmacy d-pharm 1st year by Pragati K. Mahajanpragatimahajan3
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Krashi Coaching
 
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Sapana Sha
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdfQucHHunhnh
 
Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Disha Kariya
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeThiyagu K
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3JemimahLaneBuaron
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptxVS Mahajan Coaching Centre
 
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxPOINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxSayali Powar
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesFatimaKhan178732
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDThiyagu K
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformChameera Dedduwage
 
Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactPECB
 

Recently uploaded (20)

Introduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsIntroduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The Basics
 
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...
Ecosystem Interactions Class Discussion Presentation in Blue Green Lined Styl...
 
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
 
Disha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdfDisha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdf
 
The byproduct of sericulture in different industries.pptx
The byproduct of sericulture in different industries.pptxThe byproduct of sericulture in different industries.pptx
The byproduct of sericulture in different industries.pptx
 
social pharmacy d-pharm 1st year by Pragati K. Mahajan
social pharmacy d-pharm 1st year by Pragati K. Mahajansocial pharmacy d-pharm 1st year by Pragati K. Mahajan
social pharmacy d-pharm 1st year by Pragati K. Mahajan
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
 
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdf
 
Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and Mode
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
 
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxPOINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
 
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptxINDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and Actinides
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy Reform
 
Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global Impact
 

Python mocking intro

  • 1. Python mocking intro IoC, DIP, DI and IoC containers
  • 2. Mock Objects • In Object-Oriented programming mock objects are defined as simulated objects  They mimic the behavior of real objects in controlled ways • The whole point of unit testing is isolating certain functionality (unit) and test just that. We are trying to remove all other dependencies  Sometimes this can be a database, networking or a file system, so using mock object we don’t step into the world of integration tests  Other times dependency can be just some other class or function • A mock object should be used in the situations when  The real object is slow  The real object rarely occurs and is difficult to produce artificially  The real object produces non-deterministic results  The real object does not yet exist (which often is the case in TDD)
  • 3. Some external dependencies • External resources are a common source of non-unit test dependencies – Registry and environment variables – Network connections and databases – Files and directories – Current date and time – Hardware devices – And so on… • External dependencies can often be replaced by test doubles or pre- evaluated objects – Test Double (think stunt double) is a generic term for any case where you replace a production object for testing purposes – Pre-evaluated objects can be already fetched/computed records in memory arrays
  • 4. Some various test doubles • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an In-Memory Test Database is a good example) • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test • Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it has sent • Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting Source: https://martinfowler.com/bliki/TestDouble.html
  • 5. Test doubles and unittest.mock • Mocking and related techniques may be easier in Python than in many other languages • Dependencies can be substituted without changing class design • The unittest.mock library provides a core Mock class removing the need to create a host of stubs throughout your test suite • After performing an action, you can make assertions about which attributes and methods were used and arguments they were called with • You can also specify return values and set needed attributes in the normal way • Additionally, mock provides a patch() decorator that handles patching module and class level attributes within the scope of a test for creating unique objects • Mock is relatively easy to use and is designed for use with unittest • https://docs.python.org/3/library/unittest.mock.html
  • 6. unittest.mock Quick Guide – return_value and side_effect from unittest.mock import Mock # import the Mock class from unittest.mock import MagicMock # import the MagicMock class class ProductionClass(): def __init__(self): pass # Mock and MagicMock objects create all attributes and methods as you access them and store details # of how they have been used. You can configure them, to specify return values or limit what # attributes are available, and then make assertions about how they have been used thing = ProductionClass() thing.method = MagicMock(return_value = 3) # calling method() will return 3 print(thing.method()) # print the return_value thing.method(3, 4, 5, key = 'value') thing.method.assert_called_with(3, 4, 5, key ='value') # AssertionError if different than expected call print(dir(Mock())) # show all the default mock methods / attributes # side_effect allows you to perform side effects, including raising an exception when a mock is called my_mock = Mock(side_effect = KeyError('foo')) # create a new mock object with KeyError exception # my_mock() # mock -> side_effect = KeyError exception values = {'a': 1, 'b': 2, 'c': 3} def side_effect_func(arg): return values[arg] my_mock.side_effect = side_effect_func # mock -> side_effect_func print(my_mock('a'), my_mock('b'), my_mock('c')) # print values side_effect_func(arg) my_mock.side_effect = [5, 4, 3, 2, 1] # change side_effect again for x in range(0, 5): # side_effect now returns array one by one print(my_mock()) quick_guide_mock1.py # output thing.method(): 3 dir(Mock()): ['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect'] dict: 1 2 3 range: 5 4 3 2 1
  • 7. The Mock / MagicMock classes and patch • Mock is a flexible mock object intended to replace the use of stubs and other test doubles throughout your code • Mocks are callable and create attributes as new mocks when you access them. Accessing the same attribute will always return the same mock • Mocks record how you use them, allowing you to make assertions about what your code has done to them • MagicMock is a subclass of Mock with all the magic methods (__init__, __str__, __new__, __main__, __name__, ...) pre-created and ready to use  https://docs.python.org/3/library/unittest.mock.html#magicmock-and-magic-method-support  https://rszalski.github.io/magicmethods/  You can use MagicMock without having to configure the magic methods yourself  The constructor parameters have the same meaning as for Mock • The patch() decorators makes it easy to temporarily replace classes in a particular module with a Mock object. By default patch() will create a MagicMock for you # patched classes are input @patch('my_mod.ClsName') def testFunc(MockCls): # MockCls == my_mod.ClsName assert MockCls is my_mod.ClsName # call patched class or MockCls.Mthd() my_mod.ClsName() MockCls.Mthd = Mock(return_value = ...
  • 8. Create a Mock object Create a new Mock object. Mock takes several optional arguments that specify the behaviour of the Mock object: • spec: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods). Accessing any attribute not in this list will raise an AttributeError. • If spec is an object (rather than a list of strings) then __class__ returns the class of the spec object. This allows mocks to pass isinstance() tests. • spec_set: A stricter variant of spec. If used, attempting to set or get an attribute on the mock that isn’t on the object passed as spec_set will raise an AttributeError. • side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT, the return value of this function is used as the return value. • Alternatively side_effect can be an exception class or instance. In this case the exception will be raised when the mock is called. • If side_effect is an iterable then each call to the mock will return the next value from the iterable. • A side_effect can be cleared by setting it to None. • return_value: The value returned when the mock is called. By default this is a new Mock (created on first access). See the return_value attribute. • unsafe: By default if any attribute starts with assert or assret will raise an AttributeError. Passing unsafe=True will allow access to these attributes. • wraps: Item for the mock object to wrap. If wraps is not None then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise an AttributeError). • If the mock has an explicit return_value set then calls are not passed to the wrapped object and the return_value is returned instead. • name: If the mock has a name then it will be used in the repr of the mock. This can be useful for debugging. The name is propagated to child mocks. class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs) https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock
  • 9. Mock class attributes 1 Mocks can also be called with arbitrary keyword arguments. These will be used to set attributes on the mock after it is created: • assert_called(*args, **kwargs)  Assert that the mock was called at least once. • assert_called_once(*args, **kwargs)  Assert that the mock was called exactly once. • assert_called_with(*args, **kwargs)  This method is a convenient way of asserting that calls are made in a particular way. • assert_called_once_with(*args, **kwargs)  Assert that the mock was called exactly once and that that call was with the specified arguments. • assert_any_call(*args, **kwargs)  Assert that the mock has been called with the specified arguments. • assert_has_calls(calls, any_order=False)  Assert that the mock has been called with the specified calls. The mock_calls list is checked for the calls.. • assert_not_called()  Assert that the mock was never called. • reset_mock(*, return_value=False, side_effect=False)  The reset_mock method resets all the call attributes on a mock object. • mock_add_spec(spec, spec_set=False)  Add a spec. to a mock • attach_mock(mock, attribute)  Attach a mock as an attribute of this one, replacing its name and parent. • configure_mock(**kwargs)  Set attributes on the mock through keyword arguments. # examples mock_obj.assert_not_called() mock_obj.assert_called_with(10)
  • 10. Mock class attributes 2 • __dir__()  Mock objects limit the results of dir(some_mock) to useful results • _get_child_mock(**kw)  Create the child mocks for attributes and return value • called  A boolean representing whether or not the mock object has been called • call_count  An integer telling you how many times the mock object has been called • return_value  Set this to configure the value returned by calling the mock • side_effect  This can either be a function to be called when the mock is called, an iterable or an exception (class or instance) to be raised • call_args  This is either None (if the mock hasn’t been called), or the arguments that the mock was last called with • call_args_list  This is a list of all the calls made to the mock object in sequence • method_calls  As well as tracking calls to themselves, mocks also track calls to methods and attributes, and their methods and attributes • mock_calls  mock_calls records all calls to the mock object, its methods, magic methods and return value mocks • __class__  Normally the __class__ attribute of an object will return its type. For a mock object with a spec, __class__ returns the spec class instead # examples mock_obj.return_value = 10 mock_obj.side_effect = [1, 2, 3]
  • 11. Using Mock objects • Calling  Mock objects are callable. The call will return the value set as the return_value attribute. The default return value is a new Mock object; it is created the first time the return value is accessed (either explicitly or by calling the Mock) - but it is stored and the same one returned each time  https://docs.python.org/3/library/unittest.mock.html#calling • Deleting attributes  Mock objects create attributes on demand. This allows them to pretend to be objects of any type.  You “block” attributes by deleting them. Once deleted, accessing an attribute will raise an AttributeError  https://docs.python.org/3/library/unittest.mock.html#deleting-attributes • Mock names and the name attribute  Since “name” is an argument to the Mock constructor, if you want your mock object to have a “name” attribute you can’t just pass it in at creation time. There are two alternatives. One option is to use configure_mock()  https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute • Attaching Mocks as Attributes  When you attach a mock as an attribute of another mock (or as the return value) it becomes a “child” of that mock. Calls to the child are recorded in the method_calls and mock_calls attributes of the parent. This is useful for configuring child mocks and then attaching them to the parent, or for attaching mocks to a parent that records all calls to the children and allows you to make assertions about the order of calls between mocks  https://docs.python.org/3/library/unittest.mock.html#attaching-mocks-as-attributes del mock_obj.my_attr
  • 12. Basic concepts unittest.mock – return_value from unittest import mock # import the library def print_answer(): print("42") def print_number(num): print(f"Number: {num}") m1 = mock.Mock() # The main object that the library provides is Mock and you can instantiate it without any argument print(dir(m1)) # show all the default mock methods / attributes print(m1.some_attribute) # read a non-existent attribute # Mock objects are callables, which means that they may act both as attributes and as methods. If you try to call # the mock it just returns you another mock with a name that includes parentheses to signal its callable nature print(m1.some_attribute()) # The simplest thing a mock can do for you is to return a given value every time you call it. # This is configured setting the return_value attribute of a mock object m1.some_attribute.return_value = 42 print(m1.some_attribute()) # Now the object does not return a mock object any more, instead it just returns the static value stored in the return_value attribute. # Obviously you can also store a callable such as a function or an object,and the method will return it, but it will not run it. m1.some_attribute.return_value = print_answer print(m1.some_attribute()) # As you can see calling some_attribute() just returns the value stored in return_value, that is the function itself. # To return values that come from a function we have to use a slightly more complex attribute of mock objects called side_effect. gentle_intro_to_mock1.py
  • 13. Basic concepts unittest.mock – side_effect 1 # The side_effect parameter of mock objects is a very powerful tool. It accepts 3 different flavours of objects, callables, # iterables, and exceptions, and changes its behaviour accordingly. If you pass an exception the mock will raise it m1.some_attribute.side_effect = ValueError('A custom value error') try: m1.some_attribute() except BaseException as ex: print(f"ValueError: {ex}") # If you pass an iterable, such as for example a generator, or a plain list, tuple, or similar objects, the mock will # yield the values of that iterable, i.e. return every value contained in the iterable on subsequent calls of the mock. m1.some_attribute.side_effect = range(3) print(m1.some_attribute()) print(m1.some_attribute()) print(m1.some_attribute()) # print(m1.some_attribute()) try: print(m1.some_attribute()) except BaseException as ex: print(f"StopIteration().value: {StopIteration().value}") # As promised, the mock just returns every object found in the iterable (in this case a range object) once at a time # until the generator is exhausted. According to the iterator protocol once every item has been returned # the object raises the StopIteration exception, which means that you can correctly use it in a loop. gentle_intro_to_mock1.py
  • 14. Basic concepts unittest.mock – side_effect 2 # The last and perhaps most used case is that of passing a callable to side_effect, which shamelessly executes it with # its own same parameters. This is very powerful, especially if you stop thinking about "functions" and start considering # "callables". Indeed, side_effect also accepts a class and calls it, that is it can instantiate objects. Let us consider # a simple example with a function without arguments m1.some_attribute.side_effect = print_answer m1.some_attribute() # A slightly more complex example: a function with arguments m1.some_attribute.side_effect = print_number m1.some_attribute.side_effect(5) # And finally an example with a class m1.some_attribute.side_effect = Number n1 = m1.some_attribute.side_effect(26) n1.print_value() # All the default mock methods / attributes # ['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with', # 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', # 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect'] # From: http://www.thedigitalcatonline.com/blog/2016/03/06/python-mocks-a-gentle-introduction-part-1/ class Number(object): def __init__(self, value): self._value = value def print_value(self): print("Value:", self._value) def print_answer(): print("42") def print_number(num): print(f"Number: {num}") gentle_intro_to_mock1.py
  • 15. Basic concepts unittest.mock - assert_called_with • According to Sandi Metz (programmer and author) we need to test only 3 types of messages (calls) between objects  Incoming queries (assertion on result)  Incoming commands (assertion on direct public side effects)  Outgoing commands (expectation on call and arguments)  https://www.sandimetz.com/ • What we usually are interested in when dealing with an external object is to know that a given method has been called on it • Python mocks provide the assert_called_with() method to check if a method has been called on it from unittest import mock import unittest import myobj class TestMocking(unittest.TestCase): def test_instantiation(self): external_obj = mock.Mock() myobj.MyObj(external_obj) external_obj.connect.assert_called_with() def test_setup(self): external_obj = mock.Mock() obj = myobj.MyObj(external_obj) obj.setup() external_obj.setup.assert_called_with( cache=True, max_connections=256) # AssertionError if __name__ == '__main__': unittest.main() class MyObj(): def __init__(self, repo): self._repo = repo repo.connect() def setup(self): self._repo.setup(cache=True) test_gentle_intro_to_mock1.py
  • 16. unittest.mock Mock class • We check that the Hello.bar() method is called correct with ’HELLO’ • camelCase setUp() and tearDown() can perform initialization and cleanup of the test fixture since they are called before and after the test import unittest from unittest.mock import Mock class HelloTestTest(unittest.TestCase): def setUp(self): self.hello = Hello() def tearDown(self): pass def test_foo(self): msg = 'hello' expected_bar_arg = 'HELLO' self.hello.bar = Mock() # we mock the bar() method self.hello.foo(msg) # we check that bar was called with 'HELLO' self.hello.bar.assert_called_once_with(expected_bar_arg) if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) class Hello(object): def foo(self, msg): MSG = msg.upper() self.bar(MSG) # the mocked bar() method # def bar(self, MSG): # print(MSG) test_hellomock.py
  • 17. unittest.mock MagicMock class • MagicMock is a subclass of Mock with default implementations of most of the magic methods • You can use MagicMock without having to configure the magic methods yourself import unittest from unittest.mock import MagicMock from employee import Employee class TestMocking(unittest.TestCase): def test_mock1(self): thing = Employee('Hans', 'Jones', 50) # set return value thing.method = MagicMock(return_value = 3) # call the method ret = thing.method(3, 4, 5, key='value') print(f'ret: {ret}') # check if we called correct thing.method.assert_called_with(3, 4, 5, key='value') if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) test_mock.py class Employee: """A sample Employee class""" raise_amt = 1.05 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay
  • 18. The patchers The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators. • patch() acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the target is patched with a new object. When the function/with statement exits the patch is undone. • If new is omitted, then the target is replaced with a MagicMock. If patch() is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function. If patch() is used as a context manager the created mock is returned by the context manager. • target should be a string in the form 'package.module.ClassName'. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when the decorated function is executed, not at decoration time. • The spec and spec_set keyword arguments are passed to the MagicMock if patch is creating one for you. • In addition you can pass spec=True or spec_set=True, which causes patch to pass in the object being mocked as the spec/spec_set object. • new_callable allows you to specify a different class, or callable object, that will be called to create the new object. By default MagicMock is used. • A more powerful form of spec is autospec. If you set autospec=True then the mock will be created with a spec from the object being replaced. All attributes of the mock will also have the spec of the corresponding attribute of the object being replaced. Methods and functions being mocked will have their arguments checked and will raise a TypeError if they are called with the wrong signature. For mocks replacing a class, their return value (the ‘instance’) will have the same spec as the class. See the create_autospec() function and Autospeccing. • Instead of autospec=True you can pass autospec=some_object to use an arbitrary object as the spec instead of the one being replaced. unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch
  • 19. patch.object, patch.dict and patch.multiple • Patch the named member (attribute) on an object (target) with a mock object. • patch.object() can be used as a decorator, class decorator or a context manager. Arguments new, spec, create, spec_set, autospec and new_callable have the same meaning as for patch(). Like patch(), patch.object() takes arbitrary keyword arguments for configuring the mock object it creates. • When used as a class decorator patch.object() honours patch.TEST_PREFIX for choosing which methods to wrap. • Patch a dictionary, or dictionary like object, and restore the dictionary to its original state after the test. • in_dict can be a dictionary or a mapping like container. If it is a mapping then it must at least support getting, setting and deleting items plus iterating over keys. • in_dict can also be a string specifying the name of the dictionary, which will then be fetched by importing it. • values can be a dictionary of values to set in the dictionary. values can also be an iterable of (key, value) pairs. • Perform multiple patches in a single call. It takes the object to be patched (either as an object or a string to fetch the object by importing) and keyword arguments for the patches • Use DEFAULT as the value if you want patch.multiple() to create mocks for you. In this case the created mocks are passed into a decorated function by keyword, and a dictionary is returned when patch.multiple() is used as a context manager patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch patch.dict(in_dict, values=(), clear=False, **kwargs) patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
  • 20. unittest.mock patch() function • patch() is the main mocking mechanism for the unittest.mock library • patch() works by (temporarily) changing the object that a name points to with another one • The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined class TestMocking(unittest.TestCase): # mocking MyMockedClass def test_mock2(self): # Patching a class replaces the class with a MagicMock instance with patch('__main__.MyMockedClass') as MockClass: # return_value of the mock will be used instance = MockClass.return_value instance.method.return_value = 'foo' # assert MyMockedClass() is instance of MyMockedClass self.assertIsInstance(instance, type(MyMockedClass())) self.assertEqual(MyMockedClass().method(), 'foo') self.assertEqual(instance.method(), 'foo') if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) import unittest from unittest.mock import patch class MyMockedClass: def method(self): pass test_mock.py
  • 21. unittest.mock Quick Guide – patch() from unittest.mock import Mock # import the Mock class from unittest.mock import MagicMock # import the MagicMock class from unittest.mock import patch import myobj class ProductionClass(): def method(self, a, b, c): pass # The patch() decorator / context manager makes it easy to mock classes or objects in a module under test. # The object you specify will be replaced with a mock (or other object) during the test and restored when the test ends @patch('myobj.ClassName2') @patch('myobj.ClassName1') # bottom-up passing of values def test(MockClass1, MockClass2): # patched classes are input myobj.ClassName1() # call patched class myobj.ClassName2() assert MockClass1 is myobj.ClassName1 # patched class is genuine assert MockClass2 is myobj.ClassName2 assert MockClass1.called == True # patched class have been called assert MockClass2.called == True MockClass1.return_value = 'No AssertionError!' return MockClass1.return_value print(f'test(): {test()}') # printed values from test() comes from patched objects # The patch.object() with patch.object(ProductionClass, 'method', return_value=None) as mock_method: thing = ProductionClass() thing.method(1, 2, 3) print(mock_method.assert_called_once_with(1, 2, 3)) # patched class have been called once with (1, 2, 3) and retuns None quick_guide_mock2.py myobj.py # The patch.dict() foo = {'key': 'value'} original = foo.copy() with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): assert foo == {'newkey': 'newvalue'} # foo has new values assert foo == original # output method_cs1 test(): No AssertionError! mock_method.assert_called_once_with(1, 2, 3): None class ClassName1(): def __init__(self): pass class ClassName2(): def __init__(self): pass
  • 22. unittest.mock Quick Guide – autospec # Mock supports the mocking of Python magic methods. The easiest way of using magic methods is with the MagicMock class. It allows you to do things like: mock = MagicMock() mock.__str__.return_value = 'foobarbaz' # return str(self) print(str(mock)) # 'foobarbaz' print(mock.__str__.assert_called_with()) # return str(self) # Mock allows you to assign functions (or other Mock instances) to magic methods and they will be called appropriately. # The MagicMock class is just a Mock variant that has all of the magic methods pre-created for you (well, all the useful ones anyway). # The following is an example of using magic methods with the ordinary Mock class: mock = Mock() mock.__str__ = Mock(return_value='wheeeeee') print(str(mock)) #'wheeeeee' # note the () difference mock.return_value = 'whoooooo' print(str(mock())) #'whoooooo' # For ensuring that the mock objects in your tests have the same api as the objects they are replacing, you can use auto-speccing. # Auto-speccing can be done through the autospec argument to patch, or the create_autospec() function. Auto-speccing creates mock objects that have the # same attributes and methods as the objects they are replacing, and any functions and methods # (including constructors) have the same call signature as the real object. # This ensures that your mocks will fail in the same way as your production code if they are used incorrectly: from unittest.mock import create_autospec def function(a, b, c): pass mock_function = create_autospec(function, return_value='fishy') print(mock_function(1, 2, 3)) # 'fishy' print(mock_function.assert_called_once_with(1, 2, 3)) #mock_function('wrong arguments') # TypeError: missing a required argument: 'b' # create_autospec() can also be used on classes, where it copies the signature of the # __init__ method, and on callable objects where it copies the signature of the __call__ method. str(mock): foobarbaz mock.__str__.assert_called_with(): None str(mock): wheeeeee str(mock()): whoooooo mock_function(1, 2, 3): fishy mock_function.assert_called_once_with(1, 2, 3): None quick_guide_mock2.py myobj.py
  • 23. patch() and new_callable • patch() away sys.std - we replace an object (sys.stdout) with an io.StringIO instance with the @patch decorator • patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) from io import StringIO import unittest from unittest.mock import patch class MyMockedClass: def foo_print(self): print('Something that is not going to be printed to sys.stdout') class TestMocking(unittest.TestCase): @patch('sys.stdout', new_callable=StringIO) def test_mock3(self, mock_stdout): thing = MyMockedClass() thing.foo_print() # assert mock_stdout.getvalue() == 'Somethingn' # sys.stdout.getvalue() self.assertEqual(mock_stdout.getvalue(), 'Something that is not going to be printed to sys.stdoutn') if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) test_mock.py
  • 24. Basic concepts unittest.mock – patch 1 import unittest from fileinfo import FileInfo from unittest.mock import patch from logger import Logger class TestMocking(unittest.TestCase): @classmethod def setUpClass(cls): cls.filename = 'somefile.ext' def test_init_filename(self): fi = FileInfo(self.filename) self.assertEqual(fi.filename, self.filename) def test_init_path(self): relative_path = f'../{self.filename}' fi = FileInfo(relative_path) self.assertEqual(fi.filename, self.filename) def test_get_info1(self): original_path = f'../{self.filename}' with patch('os.path.abspath') as abspath_mock: # patching os.path.abspath with patch() test_abspath = 'some/abs/path' abspath_mock.return_value = test_abspath # mocking os.path.abspath fi = FileInfo(original_path) retval = fi.get_info() self.assertEqual(retval, (self.filename, original_path, test_abspath)) import os class FileInfo: def __init__(self, path): self.original_path = path self.filename = os.path.basename(path) def get_info(self): return self.filename, self.original_path, os.path.abspath(self.filename) def get_info_size(self): return self.filename, self.original_path, os.path.abspath(self.filename), os.path.getsize(self.filename) test_gentle_intro_to_mock2.py
  • 25. Basic concepts unittest.mock – patch 2 @patch('os.path.abspath') # The patching decorator def test_get_info2(self, abspath_mock): original_path = f'../{self.filename}' test_abspath = 'some/abs/path' abspath_mock.return_value = test_abspath fi = FileInfo(original_path) self.assertEqual(fi.get_info(), (self.filename, original_path, test_abspath)) @patch('os.path.getsize') # Multiple patches @patch('os.path.abspath') # bottom-up passing of values def test_get_info3(self, abspath_mock, getsize_mock): original_path = f'../{self.filename}' test_abspath = 'some/abs/path' abspath_mock.return_value = test_abspath test_size = 1234 getsize_mock.return_value = test_size fi = FileInfo(original_path) self.assertEqual(fi.get_info_size(), (self.filename, original_path, test_abspath, test_size)) def test_get_info4(self): original_path = f'../{self.filename}' # We can write the above test using two with statements as well with patch('os.path.abspath') as abspath_mock: test_abspath = 'some/abs/path' abspath_mock.return_value = test_abspath with patch('os.path.getsize') as getsize_mock: test_size = 1234 getsize_mock.return_value = test_size fi = FileInfo(original_path) self.assertEqual(fi.get_info_size(), (self.filename, original_path, test_abspath, test_size)) test_gentle_intro_to_mock2.py
  • 26. Basic concepts unittest.mock – patch 3 # Patching immutable objects == no change after creation def test_init_logger(self): lg = Logger() self.assertEqual(lg.messages, []) # @patch('datetime.datetime.now') # def test_log1(self, mock_now): # test_now = 123 # test_message = "A test message" # mock_now.return_value = test_now # lg = Logger() # lg.log(test_message) # self.assertEqual(lg.messages, [(test_now, test_message)]) @patch('logger.datetime.datetime') def test_log2(self, mock_datetime): test_now = 123 test_message = "A test message" mock_datetime.now.return_value = test_now lg = Logger() lg.log(test_message) self.assertEqual(lg.messages, [(test_now, test_message)]) if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) import datetime class Logger: def __init__(self): self.messages = [] def log(self, message): self.messages.append((datetime.datetime.now(), message)) test_get_info1 (__main__.TestMocking) ... ok test_get_info2 (__main__.TestMocking) ... ok test_get_info3 (__main__.TestMocking) ... ok test_get_info4 (__main__.TestMocking) ... ok test_init_filename (__main__.TestMocking) ... ok test_init_logger (__main__.TestMocking) ... ok test_init_path (__main__.TestMocking) ... ok test_log2 (__main__.TestMocking) ... ok test_gentle_intro_to_mock2.py
  • 27. unittest.mock patch() a web request • To get setup and teardown code that runs in a class before tests are run we can have decorated class methods in camelCase • To mock a web site request with patch() and check URL call and returned result from unittest.mock import patch class TestEmployee(unittest.TestCase): def test_monthly_schedule(self): with patch('employee.requests.get') as mocked_get: # set return values mocked_get.return_value.ok = True mocked_get.return_value.text = 'Success' # perform a mock call with emp_1 schedule = self.emp_1.monthly_schedule('May') mocked_get.assert_called_with('http://company.com/Schafer/May') self.assertEqual(schedule, 'Success') @classmethod def setUpClass(cls): print('setupClass') @classmethod def tearDownClass(cls): print('teardownClass') test_employee.py
  • 28. Python unittest.mock example import unittest from unittest.mock import patch from employee import Employee class TestEmployee(unittest.TestCase): @classmethod def setUpClass(cls): print('setupClass') @classmethod def tearDownClass(cls): print('teardownClass') def setUp(self): print('nsetUp') self.emp_1 = Employee('Corey', 'Schafer', 50000) self.emp_2 = Employee('Sue', 'Smith', 60000) def tearDown(self): print('tearDown') #… additional code here removed for readability def test_monthly_schedule(self): with patch('employee.requests.get') as mocked_get: mocked_get.return_value.ok = True mocked_get.return_value.text = 'Success' schedule = self.emp_1.monthly_schedule('May') mocked_get.assert_called_with('http://company.com/Schafer/May') self.assertEqual(schedule, 'Success') mocked_get.return_value.ok = False schedule = self.emp_2.monthly_schedule('June') mocked_get.assert_called_with('http://company.com/Smith/June') self.assertEqual(schedule, 'Bad Response!') if __name__ == '__main__': unittest.main(argv=['first-arg-is-ignored'], exit=False) import requests class Employee: """A sample Employee class""" raise_amt = 1.05 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay @property def email(self): return 'f{self.first}.{self.last}@email.com' @property def fullname(self): return 'f{self.first} {self.last}' def apply_raise(self): self.pay = int(self.pay * self.raise_amt) #… additional code here removed for readability def monthly_schedule(self, month): response = requests.get(f'http://company.com/{self.last}/{month}') if response.ok: return response.text else: return 'Bad Response!' ----------- OUTPUT ----------- PS C:python_unittesting> python .test_employee.py -v setupClass test_apply_raise (__main__.TestEmployee) ... setUp test_apply_raise tearDown ok test_email (__main__.TestEmployee) ... setUp test_email tearDown ok test_fullname (__main__.TestEmployee) ... setUp test_fullname tearDown ok test_monthly_schedule (__main__.TestEmployee) ... setUp tearDown ok teardownClass ------------------------------------------------------ Ran 4 tests in 0.007s test_employee.py and employee.py
  • 29. IoC, DIP, DI and IoC containers • IoC – Loose coupling between classes • DIP – High-level modules should not depend on low level modules. Both ... • DI – A design pattern which implements the IoC principle to invert the creation of dependent objects • IoC container – A framework used to manage automatic dependency injection https://www.tutorialsteacher.com/ioc/
  • 30. Python and Dependency Injection 1 • Dependency Injection is a pattern that decreases coupling and increases cohesion (forming a united whole) via the Dependency Inversion Principle  The D in SOLID: https://en.wikipedia.org/wiki/Dependency_inversion_principle • The DI design pattern implements the Inversion of Control (IoC) principle to resolve dependencies: https://en.wikipedia.org/wiki/Dependency_injection  If object A (a client) depends on object B (a service), object A must not create or import object B directly - Instead object A must provide a way to inject object B  The responsibilities of objects creation and dependency injection are usually delegated to some external code - the dependency injector • There are several ways to inject a service (B) into a client (A)  by passing it (B) as an __init__ argument (constructor / initializer injection)  by setting it (B) as an attribute’s value (attribute injection)  by passing it (B) as a method’s argument (method injection) di_python.py di_python_factory.py vehicle.py
  • 31. Python and Dependency Injection 2 • The dependency injection pattern has a few strict rules that should be followed  The client (A) delegates to the dependency injector the responsibility of injecting its dependencies - the services (B)  The client should not know how to create the service, it should only know the interface of the service  The service should not know about that it is used by the client  The dependency injector knows how to create the client and the service  It also knows that the client depends on the service, and knows how to inject the service into the client  The client and service should know nothing about the dependency injector • Python Dependency Dependency Injector  https://github.com/ets-labs/python-dependency-injector • Python IoC Container  https://github.com/eyaldror/di_container di_python.py di_python_factory.py vehicle.py
  • 32. Dependency Injection (Dis)Advantages • Advantages  Control of application structure  Decreased coupling of application components  Increased code reusability  Increased testability  Increased maintainability  Reconfiguration of a system without rebuilding • Disadvantages  One need to explicitly specify the dependencies  Some extra work in the beginning
  • 33. Recommended viewing and reading • Python Mocks: a gentle introduction - Part 1 and 2  http://www.thedigitalcatonline.com/blog/2016/03/06/python-mocks-a-gentle-introduction-part-1/ • Python 3.x unittest.mock documentation  https://docs.python.org/3/library/unittest.mock.html • What the mock? - A cheatsheet for mocking in Python  https://medium.com/@yeraydiazdiaz/what-the-mock-cheatsheet-mocking-in-python- 6a71db997832  https://github.com/yeraydiazdiaz/wtmock • Test Driven Development (TDD) with Python – Mock Objects  https://rubikscode.net/2019/03/11/test-driven-development-tdd-with-python-mock-objects/ • Python Tutorial: Unit Testing Your Code with the unittest Module  https://www.youtube.com/watch?v=6tNS--WetLI • Demystifying the Patch Function  https://www.youtube.com/watch?v=ww1UsGZV8fQ