Unittest.mock is an extremely useful library which is commonly underused, this talk aims to bring clarity into stubbing in general and into medium/advanced mock features to ease and remove pain when users work with it.
Bloomberg Finance L.P. All rights reserved. Mocking of mocks A deep dive into the mock module PyConES 2018 Oct 7, 2018 Mario Corchero Senior Software Developer @mariocj89
Bloomberg Finance L.P. All rights reserved. What are testing doubles? An object that looks like the real one, but the creator is under control of its behavior.
Bloomberg Finance L.P. All rights reserved. How to create testing doubles unittest.mock.Mock() class MarioDouble: @property def nationality(self): return "Spanish" def speak(self): return “Hey, wanna come to Extremadura?”
A function takes a parameter you just want to ignore. def predict_department_expenses(budget, email_subject): ... assert EXPECTED_RESULT == predict_department_expenses(INPUT_BUDGET, None) assert EXPECTED_RESULT == predict_department_expenses(INPUT_BUDGET, “hihi”) Known as Dummy
Bloomberg Finance L.P. All rights reserved. Wrap up & conclusions • Testing doubles • Unittest.mock helps us create them • Patch can be used to use testing doubles on internal dependencies • Use spec or seal to freeze your Mock instances • Wraps allows you to easily create spies
Bloomberg Finance L.P. All rights reserved. sentinels def predict_department_expenses(budget): ... email_sender.send_email(budget) ... from unittest.mock import sentinel @unittest.mock.patch('module.to.test.email_sender', autospec=True) def test_case(mock): predict_department_expenses(“A LOT OF MONEY”) mock.assert_called_with(“A LOT OF MONEY”)
Bloomberg Finance L.P. All rights reserved. How does patch work? • Temporary replace your object with another object • By default: a new MagicMock • Just a setattr 'package.module.target' Path to set Attr to set
Bloomberg Finance L.P. All rights reserved. How does patch work? #package/module.py target = real_object 'package.module.target' Path to set Attr to set
Bloomberg Finance L.P. All rights reserved. How does patch work? #package/module.py target = real_object 'package.module.target' Path to set Attr to set # myfile.py from package.module import target print(target)
Bloomberg Finance L.P. All rights reserved. How does patch work? #package/module.py target = real_object # myfile.py from package.module import target print(target) 'myfile.target' Path to set Attr to set
Bloomberg Finance L.P. All rights reserved. Naming your mocks def printer(a, b): print(a if unknown_variable else b) printer(Mock(), Mock()) # <Mock id='140469819538008'>
Bloomberg Finance L.P. All rights reserved. from unittest.mock import Mock Mock.called() # A Mock() .assert_fake_call() # B Mock() .assret_called() # C # All? # None? Which one raises?