In [ ]:
# EXERCISE:
# Execute nosetests in this folder:
!nosetests -sv
# Exercise: review tests_lib and make the tests to pass
# Use this cell
To use real full-featured mocks use the 'mock' library:
mock library allows to replace parts of our code in a safe and easy way with
In [ ]:
from mock import MagicMock
from lib_to_test import ProductionClass
In [ ]:
from mock import MagicMock
from lib_to_test import ProductionClass
prod = ProductionClass()
prod.prod_method = MagicMock(return_value=3)
print prod.prod_method(40, 3)
prod.prod_method.assert_called_once_with(40, 3)
In [ ]:
# with side_effect we can return several values and raise exceptions too
prod.prod_method = MagicMock(side_effect=ValueError("not number"))
prod.prod_method("my_string")
In [ ]:
prod.prod_method = MagicMock(side_effect=[2, 3, 4])
prod.prod_method(34, 2)
prod.prod_method(34, 2)
prod.prod_method(34, 2)
In [ ]:
# But we are modifying our source code, we better use patch
from mock import patch
In [ ]:
import lib_to_test
# patch as decorator, provides MagicMock in function decorated
@patch('lib_to_test.ProductionClass')
def test(mockClass):
lib_to_test.ProductionClass() # Already imported in module..
print 'ProductionClass {}'.format(lib_to_test.ProductionClass)
assert mockClass is lib_to_test.ProductionClass
print mockClass.called
In [ ]:
test()
In [ ]:
print lib_to_test.ProductionClass
In [ ]:
# We can also use patch for system libraries...
import sys
# patch as context manager
with patch('sys.exit') as exitMock:
try:
sys.exit()
except SystemExit:
print "exiting programm"
exitMock.assert_called_once_with()
In [ ]:
try:
sys.exit()
except SystemExit:
print "exiting programm"
In [ ]:
# we can patch some object, dict, open and magic methods....
my_patch = patch.object(prod, 'prod_method')
method_mock = my_patch.start()
method_mock.return_value = 5000
print prod.prod_method(30, 3)
In [ ]:
# we stop the patch now ...
my_patch.stop()
print prod.prod_method
print prod.prod_method(30, 3)
In [ ]:
# WTF ??, yes before we change ProductionClass inside the module....
print prod.prod_method
prod = ProductionClass()
my_patch = patch.object(prod, 'prod_method')
method_mock = my_patch.start()
method_mock.return_value = 5000
print prod.prod_method(30, 3)
my_patch.stop()
print prod.prod_method(30, 3)
In [ ]:
# magic methods
mock = MagicMock()
mock.__str__.return_value = 'foobarbaz'
cad = str(mock)
mock.__str__.assert_called_with()
print cad
In [ ]:
# dictionary
foo = {'key': 'value'}
original = foo.copy()
with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
print "dict foo is now: {}".format(foo)
assert foo == {'newkey': 'newvalue'}
In [ ]:
print "dict foo is {}".format(foo)
assert foo == original
In [ ]:
# open function can be patched tooo....
from mock import mock_open
# write
with patch('__builtin__.open', mock_open()) as m:
with open('foo.txt', 'w') as f:
f.write('something')
print m.mock_calls
In [ ]:
import os
os.path.exists('foo.txt')
In [ ]:
# read
with patch('__builtin__.open', mock_open( read_data='foo')) as m:
with open('foo.txt') as f:
file = f.read()
print file
In [ ]:
!pip install nose-cov
!nosetests -s -v --with-cover --cover-package=lib_to_test