<jupyter_start><jupyter_text>Mock  Mock vs Mock spec<jupyter_code>import mock

class A(object):
    def __init__(self):
        self.bar = 'bar'
    def foo(self):
        return 'foo()'

print('Attribute list of the class A:')
print(dir(A))
print('')
print('Attribute list of the object A():')
print(dir(A()))<jupyter_output>Attribute list of the class A:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo']

Attribute list of the object A():
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo']<jupyter_text>Let's create two mocks of `A` class respectively with and Mock and Mock spec. Assign to `foo()` and `bar` a mocked result.<jupyter_code># With spec
a_mock = mock.Mock(spec=A)
a_mock.foo.return_value = 'foo_mock()'
a_mock.bar = 'bar_mock'

print(a_mock.foo())
print(a_mock.bar)

# Without spec
a_mock = mock.Mock()
a_mock.foo.return_value = 'foo_mock()'
a_mock.bar = 'bar_mock'

print(a_mock.foo())
print(a_mock.bar)<jupyter_output>foo_mock()
bar_mock
foo_mock()
bar_mock<jupyter_text>The problem comes when the `A` class gets changed. Without spec, the mock silently move on.<jupyter_code>class A(object):
    def __init__(self):
        self.bar2 = 'bar2'
    def foo2():
        return 'foo2()'
# Without spec
a_mock = mock.Mock()
a_mock.foo.return_value = 'foo_mock()'
a_mock.bar = 'bar_mock'

print(a_mock.foo())
print(a_mock.bar)
# With spec
a_mock = mock.Mock(spec=A)
a_mock.foo.return_value = 'foo_mock()'
a_mock.bar = 'bar_mock'

print(a_mock.foo())
print(a_mock.bar)<jupyter_output><empty_output><jupyter_text>Mock assert call<jupyter_code># Nice ways to assert if mock got called
my_mock = mock.Mock()
my_mock(1,2,3)
my_mock(1,2)

my_mock.assert_has_calls([mock.call(1, 2, 3), mock.call(1, 2)])
assert my_mock.call_count == 2<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17177656446871062, 'fraction_numerical': 0.00629987400251995, 'mean_word_length': 6.467084639498433, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '353911', 'license': 'MIT', 'n_tokens_mistral': 958, 'n_tokens_neox': 950, 'n_words': 207, 'path': 'notebooks/learning/mock.ipynb', 'repo_name': 'fsquillace/notebooks', 'size': '2381'}