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