mirror of
https://github.com/python/cpython.git
synced 2025-07-28 13:44:43 +00:00

patch, patch.object and create_autospec silently ignore misspelled arguments such as autospect, auto_spec and set_spec. This can lead to tests failing to check what they are supposed to check. This change adds a check causing a RuntimeError if the above functions get any of the above misspellings as arguments. It also adds a new argument, "unsafe", which can be set to True to disable this check. Also add "!r" to format specifiers in added error messages.
2232 lines
73 KiB
Python
2232 lines
73 KiB
Python
import copy
|
|
import re
|
|
import sys
|
|
import tempfile
|
|
|
|
from test.support import ALWAYS_EQ
|
|
import unittest
|
|
from unittest.test.testmock.support import is_instance
|
|
from unittest import mock
|
|
from unittest.mock import (
|
|
call, DEFAULT, patch, sentinel,
|
|
MagicMock, Mock, NonCallableMock,
|
|
NonCallableMagicMock, AsyncMock, _Call, _CallList,
|
|
create_autospec
|
|
)
|
|
|
|
|
|
class Iter(object):
|
|
def __init__(self):
|
|
self.thing = iter(['this', 'is', 'an', 'iter'])
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def next(self):
|
|
return next(self.thing)
|
|
|
|
__next__ = next
|
|
|
|
|
|
class Something(object):
|
|
def meth(self, a, b, c, d=None): pass
|
|
|
|
@classmethod
|
|
def cmeth(cls, a, b, c, d=None): pass
|
|
|
|
@staticmethod
|
|
def smeth(a, b, c, d=None): pass
|
|
|
|
|
|
class Typos():
|
|
autospect = None
|
|
auto_spec = None
|
|
set_spec = None
|
|
|
|
|
|
def something(a): pass
|
|
|
|
|
|
class MockTest(unittest.TestCase):
|
|
|
|
def test_all(self):
|
|
# if __all__ is badly defined then import * will raise an error
|
|
# We have to exec it because you can't import * inside a method
|
|
# in Python 3
|
|
exec("from unittest.mock import *")
|
|
|
|
|
|
def test_constructor(self):
|
|
mock = Mock()
|
|
|
|
self.assertFalse(mock.called, "called not initialised correctly")
|
|
self.assertEqual(mock.call_count, 0,
|
|
"call_count not initialised correctly")
|
|
self.assertTrue(is_instance(mock.return_value, Mock),
|
|
"return_value not initialised correctly")
|
|
|
|
self.assertEqual(mock.call_args, None,
|
|
"call_args not initialised correctly")
|
|
self.assertEqual(mock.call_args_list, [],
|
|
"call_args_list not initialised correctly")
|
|
self.assertEqual(mock.method_calls, [],
|
|
"method_calls not initialised correctly")
|
|
|
|
# Can't use hasattr for this test as it always returns True on a mock
|
|
self.assertNotIn('_items', mock.__dict__,
|
|
"default mock should not have '_items' attribute")
|
|
|
|
self.assertIsNone(mock._mock_parent,
|
|
"parent not initialised correctly")
|
|
self.assertIsNone(mock._mock_methods,
|
|
"methods not initialised correctly")
|
|
self.assertEqual(mock._mock_children, {},
|
|
"children not initialised incorrectly")
|
|
|
|
|
|
def test_return_value_in_constructor(self):
|
|
mock = Mock(return_value=None)
|
|
self.assertIsNone(mock.return_value,
|
|
"return value in constructor not honoured")
|
|
|
|
|
|
def test_change_return_value_via_delegate(self):
|
|
def f(): pass
|
|
mock = create_autospec(f)
|
|
mock.mock.return_value = 1
|
|
self.assertEqual(mock(), 1)
|
|
|
|
|
|
def test_change_side_effect_via_delegate(self):
|
|
def f(): pass
|
|
mock = create_autospec(f)
|
|
mock.mock.side_effect = TypeError()
|
|
with self.assertRaises(TypeError):
|
|
mock()
|
|
|
|
|
|
def test_repr(self):
|
|
mock = Mock(name='foo')
|
|
self.assertIn('foo', repr(mock))
|
|
self.assertIn("'%s'" % id(mock), repr(mock))
|
|
|
|
mocks = [(Mock(), 'mock'), (Mock(name='bar'), 'bar')]
|
|
for mock, name in mocks:
|
|
self.assertIn('%s.bar' % name, repr(mock.bar))
|
|
self.assertIn('%s.foo()' % name, repr(mock.foo()))
|
|
self.assertIn('%s.foo().bing' % name, repr(mock.foo().bing))
|
|
self.assertIn('%s()' % name, repr(mock()))
|
|
self.assertIn('%s()()' % name, repr(mock()()))
|
|
self.assertIn('%s()().foo.bar.baz().bing' % name,
|
|
repr(mock()().foo.bar.baz().bing))
|
|
|
|
|
|
def test_repr_with_spec(self):
|
|
class X(object):
|
|
pass
|
|
|
|
mock = Mock(spec=X)
|
|
self.assertIn(" spec='X' ", repr(mock))
|
|
|
|
mock = Mock(spec=X())
|
|
self.assertIn(" spec='X' ", repr(mock))
|
|
|
|
mock = Mock(spec_set=X)
|
|
self.assertIn(" spec_set='X' ", repr(mock))
|
|
|
|
mock = Mock(spec_set=X())
|
|
self.assertIn(" spec_set='X' ", repr(mock))
|
|
|
|
mock = Mock(spec=X, name='foo')
|
|
self.assertIn(" spec='X' ", repr(mock))
|
|
self.assertIn(" name='foo' ", repr(mock))
|
|
|
|
mock = Mock(name='foo')
|
|
self.assertNotIn("spec", repr(mock))
|
|
|
|
mock = Mock()
|
|
self.assertNotIn("spec", repr(mock))
|
|
|
|
mock = Mock(spec=['foo'])
|
|
self.assertNotIn("spec", repr(mock))
|
|
|
|
|
|
def test_side_effect(self):
|
|
mock = Mock()
|
|
|
|
def effect(*args, **kwargs):
|
|
raise SystemError('kablooie')
|
|
|
|
mock.side_effect = effect
|
|
self.assertRaises(SystemError, mock, 1, 2, fish=3)
|
|
mock.assert_called_with(1, 2, fish=3)
|
|
|
|
results = [1, 2, 3]
|
|
def effect():
|
|
return results.pop()
|
|
mock.side_effect = effect
|
|
|
|
self.assertEqual([mock(), mock(), mock()], [3, 2, 1],
|
|
"side effect not used correctly")
|
|
|
|
mock = Mock(side_effect=sentinel.SideEffect)
|
|
self.assertEqual(mock.side_effect, sentinel.SideEffect,
|
|
"side effect in constructor not used")
|
|
|
|
def side_effect():
|
|
return DEFAULT
|
|
mock = Mock(side_effect=side_effect, return_value=sentinel.RETURN)
|
|
self.assertEqual(mock(), sentinel.RETURN)
|
|
|
|
def test_autospec_side_effect(self):
|
|
# Test for issue17826
|
|
results = [1, 2, 3]
|
|
def effect():
|
|
return results.pop()
|
|
def f(): pass
|
|
|
|
mock = create_autospec(f)
|
|
mock.side_effect = [1, 2, 3]
|
|
self.assertEqual([mock(), mock(), mock()], [1, 2, 3],
|
|
"side effect not used correctly in create_autospec")
|
|
# Test where side effect is a callable
|
|
results = [1, 2, 3]
|
|
mock = create_autospec(f)
|
|
mock.side_effect = effect
|
|
self.assertEqual([mock(), mock(), mock()], [3, 2, 1],
|
|
"callable side effect not used correctly")
|
|
|
|
def test_autospec_side_effect_exception(self):
|
|
# Test for issue 23661
|
|
def f(): pass
|
|
|
|
mock = create_autospec(f)
|
|
mock.side_effect = ValueError('Bazinga!')
|
|
self.assertRaisesRegex(ValueError, 'Bazinga!', mock)
|
|
|
|
|
|
def test_reset_mock(self):
|
|
parent = Mock()
|
|
spec = ["something"]
|
|
mock = Mock(name="child", parent=parent, spec=spec)
|
|
mock(sentinel.Something, something=sentinel.SomethingElse)
|
|
something = mock.something
|
|
mock.something()
|
|
mock.side_effect = sentinel.SideEffect
|
|
return_value = mock.return_value
|
|
return_value()
|
|
|
|
mock.reset_mock()
|
|
|
|
self.assertEqual(mock._mock_name, "child",
|
|
"name incorrectly reset")
|
|
self.assertEqual(mock._mock_parent, parent,
|
|
"parent incorrectly reset")
|
|
self.assertEqual(mock._mock_methods, spec,
|
|
"methods incorrectly reset")
|
|
|
|
self.assertFalse(mock.called, "called not reset")
|
|
self.assertEqual(mock.call_count, 0, "call_count not reset")
|
|
self.assertEqual(mock.call_args, None, "call_args not reset")
|
|
self.assertEqual(mock.call_args_list, [], "call_args_list not reset")
|
|
self.assertEqual(mock.method_calls, [],
|
|
"method_calls not initialised correctly: %r != %r" %
|
|
(mock.method_calls, []))
|
|
self.assertEqual(mock.mock_calls, [])
|
|
|
|
self.assertEqual(mock.side_effect, sentinel.SideEffect,
|
|
"side_effect incorrectly reset")
|
|
self.assertEqual(mock.return_value, return_value,
|
|
"return_value incorrectly reset")
|
|
self.assertFalse(return_value.called, "return value mock not reset")
|
|
self.assertEqual(mock._mock_children, {'something': something},
|
|
"children reset incorrectly")
|
|
self.assertEqual(mock.something, something,
|
|
"children incorrectly cleared")
|
|
self.assertFalse(mock.something.called, "child not reset")
|
|
|
|
|
|
def test_reset_mock_recursion(self):
|
|
mock = Mock()
|
|
mock.return_value = mock
|
|
|
|
# used to cause recursion
|
|
mock.reset_mock()
|
|
|
|
def test_reset_mock_on_mock_open_issue_18622(self):
|
|
a = mock.mock_open()
|
|
a.reset_mock()
|
|
|
|
def test_call(self):
|
|
mock = Mock()
|
|
self.assertTrue(is_instance(mock.return_value, Mock),
|
|
"Default return_value should be a Mock")
|
|
|
|
result = mock()
|
|
self.assertEqual(mock(), result,
|
|
"different result from consecutive calls")
|
|
mock.reset_mock()
|
|
|
|
ret_val = mock(sentinel.Arg)
|
|
self.assertTrue(mock.called, "called not set")
|
|
self.assertEqual(mock.call_count, 1, "call_count incorrect")
|
|
self.assertEqual(mock.call_args, ((sentinel.Arg,), {}),
|
|
"call_args not set")
|
|
self.assertEqual(mock.call_args.args, (sentinel.Arg,),
|
|
"call_args not set")
|
|
self.assertEqual(mock.call_args.kwargs, {},
|
|
"call_args not set")
|
|
self.assertEqual(mock.call_args_list, [((sentinel.Arg,), {})],
|
|
"call_args_list not initialised correctly")
|
|
|
|
mock.return_value = sentinel.ReturnValue
|
|
ret_val = mock(sentinel.Arg, key=sentinel.KeyArg)
|
|
self.assertEqual(ret_val, sentinel.ReturnValue,
|
|
"incorrect return value")
|
|
|
|
self.assertEqual(mock.call_count, 2, "call_count incorrect")
|
|
self.assertEqual(mock.call_args,
|
|
((sentinel.Arg,), {'key': sentinel.KeyArg}),
|
|
"call_args not set")
|
|
self.assertEqual(mock.call_args_list, [
|
|
((sentinel.Arg,), {}),
|
|
((sentinel.Arg,), {'key': sentinel.KeyArg})
|
|
],
|
|
"call_args_list not set")
|
|
|
|
|
|
def test_call_args_comparison(self):
|
|
mock = Mock()
|
|
mock()
|
|
mock(sentinel.Arg)
|
|
mock(kw=sentinel.Kwarg)
|
|
mock(sentinel.Arg, kw=sentinel.Kwarg)
|
|
self.assertEqual(mock.call_args_list, [
|
|
(),
|
|
((sentinel.Arg,),),
|
|
({"kw": sentinel.Kwarg},),
|
|
((sentinel.Arg,), {"kw": sentinel.Kwarg})
|
|
])
|
|
self.assertEqual(mock.call_args,
|
|
((sentinel.Arg,), {"kw": sentinel.Kwarg}))
|
|
self.assertEqual(mock.call_args.args, (sentinel.Arg,))
|
|
self.assertEqual(mock.call_args.kwargs, {"kw": sentinel.Kwarg})
|
|
|
|
# Comparing call_args to a long sequence should not raise
|
|
# an exception. See issue 24857.
|
|
self.assertFalse(mock.call_args == "a long sequence")
|
|
|
|
|
|
def test_calls_equal_with_any(self):
|
|
# Check that equality and non-equality is consistent even when
|
|
# comparing with mock.ANY
|
|
mm = mock.MagicMock()
|
|
self.assertTrue(mm == mm)
|
|
self.assertFalse(mm != mm)
|
|
self.assertFalse(mm == mock.MagicMock())
|
|
self.assertTrue(mm != mock.MagicMock())
|
|
self.assertTrue(mm == mock.ANY)
|
|
self.assertFalse(mm != mock.ANY)
|
|
self.assertTrue(mock.ANY == mm)
|
|
self.assertFalse(mock.ANY != mm)
|
|
self.assertTrue(mm == ALWAYS_EQ)
|
|
self.assertFalse(mm != ALWAYS_EQ)
|
|
|
|
call1 = mock.call(mock.MagicMock())
|
|
call2 = mock.call(mock.ANY)
|
|
self.assertTrue(call1 == call2)
|
|
self.assertFalse(call1 != call2)
|
|
self.assertTrue(call2 == call1)
|
|
self.assertFalse(call2 != call1)
|
|
|
|
self.assertTrue(call1 == ALWAYS_EQ)
|
|
self.assertFalse(call1 != ALWAYS_EQ)
|
|
self.assertFalse(call1 == 1)
|
|
self.assertTrue(call1 != 1)
|
|
|
|
|
|
def test_assert_called_with(self):
|
|
mock = Mock()
|
|
mock()
|
|
|
|
# Will raise an exception if it fails
|
|
mock.assert_called_with()
|
|
self.assertRaises(AssertionError, mock.assert_called_with, 1)
|
|
|
|
mock.reset_mock()
|
|
self.assertRaises(AssertionError, mock.assert_called_with)
|
|
|
|
mock(1, 2, 3, a='fish', b='nothing')
|
|
mock.assert_called_with(1, 2, 3, a='fish', b='nothing')
|
|
|
|
|
|
def test_assert_called_with_any(self):
|
|
m = MagicMock()
|
|
m(MagicMock())
|
|
m.assert_called_with(mock.ANY)
|
|
|
|
|
|
def test_assert_called_with_function_spec(self):
|
|
def f(a, b, c, d=None): pass
|
|
|
|
mock = Mock(spec=f)
|
|
|
|
mock(1, b=2, c=3)
|
|
mock.assert_called_with(1, 2, 3)
|
|
mock.assert_called_with(a=1, b=2, c=3)
|
|
self.assertRaises(AssertionError, mock.assert_called_with,
|
|
1, b=3, c=2)
|
|
# Expected call doesn't match the spec's signature
|
|
with self.assertRaises(AssertionError) as cm:
|
|
mock.assert_called_with(e=8)
|
|
self.assertIsInstance(cm.exception.__cause__, TypeError)
|
|
|
|
|
|
def test_assert_called_with_method_spec(self):
|
|
def _check(mock):
|
|
mock(1, b=2, c=3)
|
|
mock.assert_called_with(1, 2, 3)
|
|
mock.assert_called_with(a=1, b=2, c=3)
|
|
self.assertRaises(AssertionError, mock.assert_called_with,
|
|
1, b=3, c=2)
|
|
|
|
mock = Mock(spec=Something().meth)
|
|
_check(mock)
|
|
mock = Mock(spec=Something.cmeth)
|
|
_check(mock)
|
|
mock = Mock(spec=Something().cmeth)
|
|
_check(mock)
|
|
mock = Mock(spec=Something.smeth)
|
|
_check(mock)
|
|
mock = Mock(spec=Something().smeth)
|
|
_check(mock)
|
|
|
|
|
|
def test_assert_called_exception_message(self):
|
|
msg = "Expected '{0}' to have been called"
|
|
with self.assertRaisesRegex(AssertionError, msg.format('mock')):
|
|
Mock().assert_called()
|
|
with self.assertRaisesRegex(AssertionError, msg.format('test_name')):
|
|
Mock(name="test_name").assert_called()
|
|
|
|
|
|
def test_assert_called_once_with(self):
|
|
mock = Mock()
|
|
mock()
|
|
|
|
# Will raise an exception if it fails
|
|
mock.assert_called_once_with()
|
|
|
|
mock()
|
|
self.assertRaises(AssertionError, mock.assert_called_once_with)
|
|
|
|
mock.reset_mock()
|
|
self.assertRaises(AssertionError, mock.assert_called_once_with)
|
|
|
|
mock('foo', 'bar', baz=2)
|
|
mock.assert_called_once_with('foo', 'bar', baz=2)
|
|
|
|
mock.reset_mock()
|
|
mock('foo', 'bar', baz=2)
|
|
self.assertRaises(
|
|
AssertionError,
|
|
lambda: mock.assert_called_once_with('bob', 'bar', baz=2)
|
|
)
|
|
|
|
def test_assert_called_once_with_call_list(self):
|
|
m = Mock()
|
|
m(1)
|
|
m(2)
|
|
self.assertRaisesRegex(AssertionError,
|
|
re.escape("Calls: [call(1), call(2)]"),
|
|
lambda: m.assert_called_once_with(2))
|
|
|
|
|
|
def test_assert_called_once_with_function_spec(self):
|
|
def f(a, b, c, d=None): pass
|
|
|
|
mock = Mock(spec=f)
|
|
|
|
mock(1, b=2, c=3)
|
|
mock.assert_called_once_with(1, 2, 3)
|
|
mock.assert_called_once_with(a=1, b=2, c=3)
|
|
self.assertRaises(AssertionError, mock.assert_called_once_with,
|
|
1, b=3, c=2)
|
|
# Expected call doesn't match the spec's signature
|
|
with self.assertRaises(AssertionError) as cm:
|
|
mock.assert_called_once_with(e=8)
|
|
self.assertIsInstance(cm.exception.__cause__, TypeError)
|
|
# Mock called more than once => always fails
|
|
mock(4, 5, 6)
|
|
self.assertRaises(AssertionError, mock.assert_called_once_with,
|
|
1, 2, 3)
|
|
self.assertRaises(AssertionError, mock.assert_called_once_with,
|
|
4, 5, 6)
|
|
|
|
|
|
def test_attribute_access_returns_mocks(self):
|
|
mock = Mock()
|
|
something = mock.something
|
|
self.assertTrue(is_instance(something, Mock), "attribute isn't a mock")
|
|
self.assertEqual(mock.something, something,
|
|
"different attributes returned for same name")
|
|
|
|
# Usage example
|
|
mock = Mock()
|
|
mock.something.return_value = 3
|
|
|
|
self.assertEqual(mock.something(), 3, "method returned wrong value")
|
|
self.assertTrue(mock.something.called,
|
|
"method didn't record being called")
|
|
|
|
|
|
def test_attributes_have_name_and_parent_set(self):
|
|
mock = Mock()
|
|
something = mock.something
|
|
|
|
self.assertEqual(something._mock_name, "something",
|
|
"attribute name not set correctly")
|
|
self.assertEqual(something._mock_parent, mock,
|
|
"attribute parent not set correctly")
|
|
|
|
|
|
def test_method_calls_recorded(self):
|
|
mock = Mock()
|
|
mock.something(3, fish=None)
|
|
mock.something_else.something(6, cake=sentinel.Cake)
|
|
|
|
self.assertEqual(mock.something_else.method_calls,
|
|
[("something", (6,), {'cake': sentinel.Cake})],
|
|
"method calls not recorded correctly")
|
|
self.assertEqual(mock.method_calls, [
|
|
("something", (3,), {'fish': None}),
|
|
("something_else.something", (6,), {'cake': sentinel.Cake})
|
|
],
|
|
"method calls not recorded correctly")
|
|
|
|
|
|
def test_method_calls_compare_easily(self):
|
|
mock = Mock()
|
|
mock.something()
|
|
self.assertEqual(mock.method_calls, [('something',)])
|
|
self.assertEqual(mock.method_calls, [('something', (), {})])
|
|
|
|
mock = Mock()
|
|
mock.something('different')
|
|
self.assertEqual(mock.method_calls, [('something', ('different',))])
|
|
self.assertEqual(mock.method_calls,
|
|
[('something', ('different',), {})])
|
|
|
|
mock = Mock()
|
|
mock.something(x=1)
|
|
self.assertEqual(mock.method_calls, [('something', {'x': 1})])
|
|
self.assertEqual(mock.method_calls, [('something', (), {'x': 1})])
|
|
|
|
mock = Mock()
|
|
mock.something('different', some='more')
|
|
self.assertEqual(mock.method_calls, [
|
|
('something', ('different',), {'some': 'more'})
|
|
])
|
|
|
|
|
|
def test_only_allowed_methods_exist(self):
|
|
for spec in ['something'], ('something',):
|
|
for arg in 'spec', 'spec_set':
|
|
mock = Mock(**{arg: spec})
|
|
|
|
# this should be allowed
|
|
mock.something
|
|
self.assertRaisesRegex(
|
|
AttributeError,
|
|
"Mock object has no attribute 'something_else'",
|
|
getattr, mock, 'something_else'
|
|
)
|
|
|
|
|
|
def test_from_spec(self):
|
|
class Something(object):
|
|
x = 3
|
|
__something__ = None
|
|
def y(self): pass
|
|
|
|
def test_attributes(mock):
|
|
# should work
|
|
mock.x
|
|
mock.y
|
|
mock.__something__
|
|
self.assertRaisesRegex(
|
|
AttributeError,
|
|
"Mock object has no attribute 'z'",
|
|
getattr, mock, 'z'
|
|
)
|
|
self.assertRaisesRegex(
|
|
AttributeError,
|
|
"Mock object has no attribute '__foobar__'",
|
|
getattr, mock, '__foobar__'
|
|
)
|
|
|
|
test_attributes(Mock(spec=Something))
|
|
test_attributes(Mock(spec=Something()))
|
|
|
|
|
|
def test_wraps_calls(self):
|
|
real = Mock()
|
|
|
|
mock = Mock(wraps=real)
|
|
self.assertEqual(mock(), real())
|
|
|
|
real.reset_mock()
|
|
|
|
mock(1, 2, fish=3)
|
|
real.assert_called_with(1, 2, fish=3)
|
|
|
|
|
|
def test_wraps_prevents_automatic_creation_of_mocks(self):
|
|
class Real(object):
|
|
pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
|
|
self.assertRaises(AttributeError, lambda: mock.new_attr())
|
|
|
|
|
|
def test_wraps_call_with_nondefault_return_value(self):
|
|
real = Mock()
|
|
|
|
mock = Mock(wraps=real)
|
|
mock.return_value = 3
|
|
|
|
self.assertEqual(mock(), 3)
|
|
self.assertFalse(real.called)
|
|
|
|
|
|
def test_wraps_attributes(self):
|
|
class Real(object):
|
|
attribute = Mock()
|
|
|
|
real = Real()
|
|
|
|
mock = Mock(wraps=real)
|
|
self.assertEqual(mock.attribute(), real.attribute())
|
|
self.assertRaises(AttributeError, lambda: mock.fish)
|
|
|
|
self.assertNotEqual(mock.attribute, real.attribute)
|
|
result = mock.attribute.frog(1, 2, fish=3)
|
|
Real.attribute.frog.assert_called_with(1, 2, fish=3)
|
|
self.assertEqual(result, Real.attribute.frog())
|
|
|
|
|
|
def test_customize_wrapped_object_with_side_effect_iterable_with_default(self):
|
|
class Real(object):
|
|
def method(self):
|
|
return sentinel.ORIGINAL_VALUE
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE1)
|
|
self.assertEqual(mock.method(), sentinel.ORIGINAL_VALUE)
|
|
self.assertRaises(StopIteration, mock.method)
|
|
|
|
|
|
def test_customize_wrapped_object_with_side_effect_iterable(self):
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE1)
|
|
self.assertEqual(mock.method(), sentinel.VALUE2)
|
|
self.assertRaises(StopIteration, mock.method)
|
|
|
|
|
|
def test_customize_wrapped_object_with_side_effect_exception(self):
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = RuntimeError
|
|
|
|
self.assertRaises(RuntimeError, mock.method)
|
|
|
|
|
|
def test_customize_wrapped_object_with_side_effect_function(self):
|
|
class Real(object):
|
|
def method(self): pass
|
|
def side_effect():
|
|
return sentinel.VALUE
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = side_effect
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE)
|
|
|
|
|
|
def test_customize_wrapped_object_with_return_value(self):
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.return_value = sentinel.VALUE
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE)
|
|
|
|
|
|
def test_customize_wrapped_object_with_return_value_and_side_effect(self):
|
|
# side_effect should always take precedence over return_value.
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
|
|
mock.method.return_value = sentinel.WRONG_VALUE
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE1)
|
|
self.assertEqual(mock.method(), sentinel.VALUE2)
|
|
self.assertRaises(StopIteration, mock.method)
|
|
|
|
|
|
def test_customize_wrapped_object_with_return_value_and_side_effect2(self):
|
|
# side_effect can return DEFAULT to default to return_value
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = lambda: DEFAULT
|
|
mock.method.return_value = sentinel.VALUE
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE)
|
|
|
|
|
|
def test_customize_wrapped_object_with_return_value_and_side_effect_default(self):
|
|
class Real(object):
|
|
def method(self): pass
|
|
|
|
real = Real()
|
|
mock = Mock(wraps=real)
|
|
mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
|
|
mock.method.return_value = sentinel.RETURN
|
|
|
|
self.assertEqual(mock.method(), sentinel.VALUE1)
|
|
self.assertEqual(mock.method(), sentinel.RETURN)
|
|
self.assertRaises(StopIteration, mock.method)
|
|
|
|
|
|
def test_magic_method_wraps_dict(self):
|
|
# bpo-25597: MagicMock with wrap doesn't call wrapped object's
|
|
# method for magic methods with default values.
|
|
data = {'foo': 'bar'}
|
|
|
|
wrapped_dict = MagicMock(wraps=data)
|
|
self.assertEqual(wrapped_dict.get('foo'), 'bar')
|
|
# Accessing key gives a MagicMock
|
|
self.assertIsInstance(wrapped_dict['foo'], MagicMock)
|
|
# __contains__ method has a default value of False
|
|
self.assertFalse('foo' in wrapped_dict)
|
|
|
|
# return_value is non-sentinel and takes precedence over wrapped value.
|
|
wrapped_dict.get.return_value = 'return_value'
|
|
self.assertEqual(wrapped_dict.get('foo'), 'return_value')
|
|
|
|
# return_value is sentinel and hence wrapped value is returned.
|
|
wrapped_dict.get.return_value = sentinel.DEFAULT
|
|
self.assertEqual(wrapped_dict.get('foo'), 'bar')
|
|
|
|
self.assertEqual(wrapped_dict.get('baz'), None)
|
|
self.assertIsInstance(wrapped_dict['baz'], MagicMock)
|
|
self.assertFalse('bar' in wrapped_dict)
|
|
|
|
data['baz'] = 'spam'
|
|
self.assertEqual(wrapped_dict.get('baz'), 'spam')
|
|
self.assertIsInstance(wrapped_dict['baz'], MagicMock)
|
|
self.assertFalse('bar' in wrapped_dict)
|
|
|
|
del data['baz']
|
|
self.assertEqual(wrapped_dict.get('baz'), None)
|
|
|
|
|
|
def test_magic_method_wraps_class(self):
|
|
|
|
class Foo:
|
|
|
|
def __getitem__(self, index):
|
|
return index
|
|
|
|
def __custom_method__(self):
|
|
return "foo"
|
|
|
|
|
|
klass = MagicMock(wraps=Foo)
|
|
obj = klass()
|
|
self.assertEqual(obj.__getitem__(2), 2)
|
|
self.assertEqual(obj[2], 2)
|
|
self.assertEqual(obj.__custom_method__(), "foo")
|
|
|
|
|
|
def test_exceptional_side_effect(self):
|
|
mock = Mock(side_effect=AttributeError)
|
|
self.assertRaises(AttributeError, mock)
|
|
|
|
mock = Mock(side_effect=AttributeError('foo'))
|
|
self.assertRaises(AttributeError, mock)
|
|
|
|
|
|
def test_baseexceptional_side_effect(self):
|
|
mock = Mock(side_effect=KeyboardInterrupt)
|
|
self.assertRaises(KeyboardInterrupt, mock)
|
|
|
|
mock = Mock(side_effect=KeyboardInterrupt('foo'))
|
|
self.assertRaises(KeyboardInterrupt, mock)
|
|
|
|
|
|
def test_assert_called_with_message(self):
|
|
mock = Mock()
|
|
self.assertRaisesRegex(AssertionError, 'not called',
|
|
mock.assert_called_with)
|
|
|
|
|
|
def test_assert_called_once_with_message(self):
|
|
mock = Mock(name='geoffrey')
|
|
self.assertRaisesRegex(AssertionError,
|
|
r"Expected 'geoffrey' to be called once\.",
|
|
mock.assert_called_once_with)
|
|
|
|
|
|
def test__name__(self):
|
|
mock = Mock()
|
|
self.assertRaises(AttributeError, lambda: mock.__name__)
|
|
|
|
mock.__name__ = 'foo'
|
|
self.assertEqual(mock.__name__, 'foo')
|
|
|
|
|
|
def test_spec_list_subclass(self):
|
|
class Sub(list):
|
|
pass
|
|
mock = Mock(spec=Sub(['foo']))
|
|
|
|
mock.append(3)
|
|
mock.append.assert_called_with(3)
|
|
self.assertRaises(AttributeError, getattr, mock, 'foo')
|
|
|
|
|
|
def test_spec_class(self):
|
|
class X(object):
|
|
pass
|
|
|
|
mock = Mock(spec=X)
|
|
self.assertIsInstance(mock, X)
|
|
|
|
mock = Mock(spec=X())
|
|
self.assertIsInstance(mock, X)
|
|
|
|
self.assertIs(mock.__class__, X)
|
|
self.assertEqual(Mock().__class__.__name__, 'Mock')
|
|
|
|
mock = Mock(spec_set=X)
|
|
self.assertIsInstance(mock, X)
|
|
|
|
mock = Mock(spec_set=X())
|
|
self.assertIsInstance(mock, X)
|
|
|
|
|
|
def test_spec_class_no_object_base(self):
|
|
class X:
|
|
pass
|
|
|
|
mock = Mock(spec=X)
|
|
self.assertIsInstance(mock, X)
|
|
|
|
mock = Mock(spec=X())
|
|
self.assertIsInstance(mock, X)
|
|
|
|
self.assertIs(mock.__class__, X)
|
|
self.assertEqual(Mock().__class__.__name__, 'Mock')
|
|
|
|
mock = Mock(spec_set=X)
|
|
self.assertIsInstance(mock, X)
|
|
|
|
mock = Mock(spec_set=X())
|
|
self.assertIsInstance(mock, X)
|
|
|
|
|
|
def test_setting_attribute_with_spec_set(self):
|
|
class X(object):
|
|
y = 3
|
|
|
|
mock = Mock(spec=X)
|
|
mock.x = 'foo'
|
|
|
|
mock = Mock(spec_set=X)
|
|
def set_attr():
|
|
mock.x = 'foo'
|
|
|
|
mock.y = 'foo'
|
|
self.assertRaises(AttributeError, set_attr)
|
|
|
|
|
|
def test_copy(self):
|
|
current = sys.getrecursionlimit()
|
|
self.addCleanup(sys.setrecursionlimit, current)
|
|
|
|
# can't use sys.maxint as this doesn't exist in Python 3
|
|
sys.setrecursionlimit(int(10e8))
|
|
# this segfaults without the fix in place
|
|
copy.copy(Mock())
|
|
|
|
|
|
def test_subclass_with_properties(self):
|
|
class SubClass(Mock):
|
|
def _get(self):
|
|
return 3
|
|
def _set(self, value):
|
|
raise NameError('strange error')
|
|
some_attribute = property(_get, _set)
|
|
|
|
s = SubClass(spec_set=SubClass)
|
|
self.assertEqual(s.some_attribute, 3)
|
|
|
|
def test():
|
|
s.some_attribute = 3
|
|
self.assertRaises(NameError, test)
|
|
|
|
def test():
|
|
s.foo = 'bar'
|
|
self.assertRaises(AttributeError, test)
|
|
|
|
|
|
def test_setting_call(self):
|
|
mock = Mock()
|
|
def __call__(self, a):
|
|
self._increment_mock_call(a)
|
|
return self._mock_call(a)
|
|
|
|
type(mock).__call__ = __call__
|
|
mock('one')
|
|
mock.assert_called_with('one')
|
|
|
|
self.assertRaises(TypeError, mock, 'one', 'two')
|
|
|
|
|
|
def test_dir(self):
|
|
mock = Mock()
|
|
attrs = set(dir(mock))
|
|
type_attrs = set([m for m in dir(Mock) if not m.startswith('_')])
|
|
|
|
# all public attributes from the type are included
|
|
self.assertEqual(set(), type_attrs - attrs)
|
|
|
|
# creates these attributes
|
|
mock.a, mock.b
|
|
self.assertIn('a', dir(mock))
|
|
self.assertIn('b', dir(mock))
|
|
|
|
# instance attributes
|
|
mock.c = mock.d = None
|
|
self.assertIn('c', dir(mock))
|
|
self.assertIn('d', dir(mock))
|
|
|
|
# magic methods
|
|
mock.__iter__ = lambda s: iter([])
|
|
self.assertIn('__iter__', dir(mock))
|
|
|
|
|
|
def test_dir_from_spec(self):
|
|
mock = Mock(spec=unittest.TestCase)
|
|
testcase_attrs = set(dir(unittest.TestCase))
|
|
attrs = set(dir(mock))
|
|
|
|
# all attributes from the spec are included
|
|
self.assertEqual(set(), testcase_attrs - attrs)
|
|
|
|
# shadow a sys attribute
|
|
mock.version = 3
|
|
self.assertEqual(dir(mock).count('version'), 1)
|
|
|
|
|
|
def test_filter_dir(self):
|
|
patcher = patch.object(mock, 'FILTER_DIR', False)
|
|
patcher.start()
|
|
try:
|
|
attrs = set(dir(Mock()))
|
|
type_attrs = set(dir(Mock))
|
|
|
|
# ALL attributes from the type are included
|
|
self.assertEqual(set(), type_attrs - attrs)
|
|
finally:
|
|
patcher.stop()
|
|
|
|
|
|
def test_dir_does_not_include_deleted_attributes(self):
|
|
mock = Mock()
|
|
mock.child.return_value = 1
|
|
|
|
self.assertIn('child', dir(mock))
|
|
del mock.child
|
|
self.assertNotIn('child', dir(mock))
|
|
|
|
|
|
def test_configure_mock(self):
|
|
mock = Mock(foo='bar')
|
|
self.assertEqual(mock.foo, 'bar')
|
|
|
|
mock = MagicMock(foo='bar')
|
|
self.assertEqual(mock.foo, 'bar')
|
|
|
|
kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33,
|
|
'foo': MagicMock()}
|
|
mock = Mock(**kwargs)
|
|
self.assertRaises(KeyError, mock)
|
|
self.assertEqual(mock.foo.bar(), 33)
|
|
self.assertIsInstance(mock.foo, MagicMock)
|
|
|
|
mock = Mock()
|
|
mock.configure_mock(**kwargs)
|
|
self.assertRaises(KeyError, mock)
|
|
self.assertEqual(mock.foo.bar(), 33)
|
|
self.assertIsInstance(mock.foo, MagicMock)
|
|
|
|
|
|
def assertRaisesWithMsg(self, exception, message, func, *args, **kwargs):
|
|
# needed because assertRaisesRegex doesn't work easily with newlines
|
|
with self.assertRaises(exception) as context:
|
|
func(*args, **kwargs)
|
|
msg = str(context.exception)
|
|
self.assertEqual(msg, message)
|
|
|
|
|
|
def test_assert_called_with_failure_message(self):
|
|
mock = NonCallableMock()
|
|
|
|
actual = 'not called.'
|
|
expected = "mock(1, '2', 3, bar='foo')"
|
|
message = 'expected call not found.\nExpected: %s\nActual: %s'
|
|
self.assertRaisesWithMsg(
|
|
AssertionError, message % (expected, actual),
|
|
mock.assert_called_with, 1, '2', 3, bar='foo'
|
|
)
|
|
|
|
mock.foo(1, '2', 3, foo='foo')
|
|
|
|
|
|
asserters = [
|
|
mock.foo.assert_called_with, mock.foo.assert_called_once_with
|
|
]
|
|
for meth in asserters:
|
|
actual = "foo(1, '2', 3, foo='foo')"
|
|
expected = "foo(1, '2', 3, bar='foo')"
|
|
message = 'expected call not found.\nExpected: %s\nActual: %s'
|
|
self.assertRaisesWithMsg(
|
|
AssertionError, message % (expected, actual),
|
|
meth, 1, '2', 3, bar='foo'
|
|
)
|
|
|
|
# just kwargs
|
|
for meth in asserters:
|
|
actual = "foo(1, '2', 3, foo='foo')"
|
|
expected = "foo(bar='foo')"
|
|
message = 'expected call not found.\nExpected: %s\nActual: %s'
|
|
self.assertRaisesWithMsg(
|
|
AssertionError, message % (expected, actual),
|
|
meth, bar='foo'
|
|
)
|
|
|
|
# just args
|
|
for meth in asserters:
|
|
actual = "foo(1, '2', 3, foo='foo')"
|
|
expected = "foo(1, 2, 3)"
|
|
message = 'expected call not found.\nExpected: %s\nActual: %s'
|
|
self.assertRaisesWithMsg(
|
|
AssertionError, message % (expected, actual),
|
|
meth, 1, 2, 3
|
|
)
|
|
|
|
# empty
|
|
for meth in asserters:
|
|
actual = "foo(1, '2', 3, foo='foo')"
|
|
expected = "foo()"
|
|
message = 'expected call not found.\nExpected: %s\nActual: %s'
|
|
self.assertRaisesWithMsg(
|
|
AssertionError, message % (expected, actual), meth
|
|
)
|
|
|
|
|
|
def test_mock_calls(self):
|
|
mock = MagicMock()
|
|
|
|
# need to do this because MagicMock.mock_calls used to just return
|
|
# a MagicMock which also returned a MagicMock when __eq__ was called
|
|
self.assertIs(mock.mock_calls == [], True)
|
|
|
|
mock = MagicMock()
|
|
mock()
|
|
expected = [('', (), {})]
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
|
|
mock.foo()
|
|
expected.append(call.foo())
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
# intermediate mock_calls work too
|
|
self.assertEqual(mock.foo.mock_calls, [('', (), {})])
|
|
|
|
mock = MagicMock()
|
|
mock().foo(1, 2, 3, a=4, b=5)
|
|
expected = [
|
|
('', (), {}), ('().foo', (1, 2, 3), dict(a=4, b=5))
|
|
]
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
self.assertEqual(mock.return_value.foo.mock_calls,
|
|
[('', (1, 2, 3), dict(a=4, b=5))])
|
|
self.assertEqual(mock.return_value.mock_calls,
|
|
[('foo', (1, 2, 3), dict(a=4, b=5))])
|
|
|
|
mock = MagicMock()
|
|
mock().foo.bar().baz()
|
|
expected = [
|
|
('', (), {}), ('().foo.bar', (), {}),
|
|
('().foo.bar().baz', (), {})
|
|
]
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
self.assertEqual(mock().mock_calls,
|
|
call.foo.bar().baz().call_list())
|
|
|
|
for kwargs in dict(), dict(name='bar'):
|
|
mock = MagicMock(**kwargs)
|
|
int(mock.foo)
|
|
expected = [('foo.__int__', (), {})]
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
|
|
mock = MagicMock(**kwargs)
|
|
mock.a()()
|
|
expected = [('a', (), {}), ('a()', (), {})]
|
|
self.assertEqual(mock.mock_calls, expected)
|
|
self.assertEqual(mock.a().mock_calls, [call()])
|
|
|
|
mock = MagicMock(**kwargs)
|
|
mock(1)(2)(3)
|
|
self.assertEqual(mock.mock_calls, call(1)(2)(3).call_list())
|
|
self.assertEqual(mock().mock_calls, call(2)(3).call_list())
|
|
self.assertEqual(mock()().mock_calls, call(3).call_list())
|
|
|
|
mock = MagicMock(**kwargs)
|
|
mock(1)(2)(3).a.b.c(4)
|
|
self.assertEqual(mock.mock_calls,
|
|
call(1)(2)(3).a.b.c(4).call_list())
|
|
self.assertEqual(mock().mock_calls,
|
|
call(2)(3).a.b.c(4).call_list())
|
|
self.assertEqual(mock()().mock_calls,
|
|
call(3).a.b.c(4).call_list())
|
|
|
|
mock = MagicMock(**kwargs)
|
|
int(mock().foo.bar().baz())
|
|
last_call = ('().foo.bar().baz().__int__', (), {})
|
|
self.assertEqual(mock.mock_calls[-1], last_call)
|
|
self.assertEqual(mock().mock_calls,
|
|
call.foo.bar().baz().__int__().call_list())
|
|
self.assertEqual(mock().foo.bar().mock_calls,
|
|
call.baz().__int__().call_list())
|
|
self.assertEqual(mock().foo.bar().baz.mock_calls,
|
|
call().__int__().call_list())
|
|
|
|
|
|
def test_child_mock_call_equal(self):
|
|
m = Mock()
|
|
result = m()
|
|
result.wibble()
|
|
# parent looks like this:
|
|
self.assertEqual(m.mock_calls, [call(), call().wibble()])
|
|
# but child should look like this:
|
|
self.assertEqual(result.mock_calls, [call.wibble()])
|
|
|
|
|
|
def test_mock_call_not_equal_leaf(self):
|
|
m = Mock()
|
|
m.foo().something()
|
|
self.assertNotEqual(m.mock_calls[1], call.foo().different())
|
|
self.assertEqual(m.mock_calls[0], call.foo())
|
|
|
|
|
|
def test_mock_call_not_equal_non_leaf(self):
|
|
m = Mock()
|
|
m.foo().bar()
|
|
self.assertNotEqual(m.mock_calls[1], call.baz().bar())
|
|
self.assertNotEqual(m.mock_calls[0], call.baz())
|
|
|
|
|
|
def test_mock_call_not_equal_non_leaf_params_different(self):
|
|
m = Mock()
|
|
m.foo(x=1).bar()
|
|
# This isn't ideal, but there's no way to fix it without breaking backwards compatibility:
|
|
self.assertEqual(m.mock_calls[1], call.foo(x=2).bar())
|
|
|
|
|
|
def test_mock_call_not_equal_non_leaf_attr(self):
|
|
m = Mock()
|
|
m.foo.bar()
|
|
self.assertNotEqual(m.mock_calls[0], call.baz.bar())
|
|
|
|
|
|
def test_mock_call_not_equal_non_leaf_call_versus_attr(self):
|
|
m = Mock()
|
|
m.foo.bar()
|
|
self.assertNotEqual(m.mock_calls[0], call.foo().bar())
|
|
|
|
|
|
def test_mock_call_repr(self):
|
|
m = Mock()
|
|
m.foo().bar().baz.bob()
|
|
self.assertEqual(repr(m.mock_calls[0]), 'call.foo()')
|
|
self.assertEqual(repr(m.mock_calls[1]), 'call.foo().bar()')
|
|
self.assertEqual(repr(m.mock_calls[2]), 'call.foo().bar().baz.bob()')
|
|
|
|
|
|
def test_mock_call_repr_loop(self):
|
|
m = Mock()
|
|
m.foo = m
|
|
repr(m.foo())
|
|
self.assertRegex(repr(m.foo()), r"<Mock name='mock\(\)' id='\d+'>")
|
|
|
|
|
|
def test_mock_calls_contains(self):
|
|
m = Mock()
|
|
self.assertFalse([call()] in m.mock_calls)
|
|
|
|
|
|
def test_subclassing(self):
|
|
class Subclass(Mock):
|
|
pass
|
|
|
|
mock = Subclass()
|
|
self.assertIsInstance(mock.foo, Subclass)
|
|
self.assertIsInstance(mock(), Subclass)
|
|
|
|
class Subclass(Mock):
|
|
def _get_child_mock(self, **kwargs):
|
|
return Mock(**kwargs)
|
|
|
|
mock = Subclass()
|
|
self.assertNotIsInstance(mock.foo, Subclass)
|
|
self.assertNotIsInstance(mock(), Subclass)
|
|
|
|
|
|
def test_arg_lists(self):
|
|
mocks = [
|
|
Mock(),
|
|
MagicMock(),
|
|
NonCallableMock(),
|
|
NonCallableMagicMock()
|
|
]
|
|
|
|
def assert_attrs(mock):
|
|
names = 'call_args_list', 'method_calls', 'mock_calls'
|
|
for name in names:
|
|
attr = getattr(mock, name)
|
|
self.assertIsInstance(attr, _CallList)
|
|
self.assertIsInstance(attr, list)
|
|
self.assertEqual(attr, [])
|
|
|
|
for mock in mocks:
|
|
assert_attrs(mock)
|
|
|
|
if callable(mock):
|
|
mock()
|
|
mock(1, 2)
|
|
mock(a=3)
|
|
|
|
mock.reset_mock()
|
|
assert_attrs(mock)
|
|
|
|
mock.foo()
|
|
mock.foo.bar(1, a=3)
|
|
mock.foo(1).bar().baz(3)
|
|
|
|
mock.reset_mock()
|
|
assert_attrs(mock)
|
|
|
|
|
|
def test_call_args_two_tuple(self):
|
|
mock = Mock()
|
|
mock(1, a=3)
|
|
mock(2, b=4)
|
|
|
|
self.assertEqual(len(mock.call_args), 2)
|
|
self.assertEqual(mock.call_args.args, (2,))
|
|
self.assertEqual(mock.call_args.kwargs, dict(b=4))
|
|
|
|
expected_list = [((1,), dict(a=3)), ((2,), dict(b=4))]
|
|
for expected, call_args in zip(expected_list, mock.call_args_list):
|
|
self.assertEqual(len(call_args), 2)
|
|
self.assertEqual(expected[0], call_args[0])
|
|
self.assertEqual(expected[1], call_args[1])
|
|
|
|
|
|
def test_side_effect_iterator(self):
|
|
mock = Mock(side_effect=iter([1, 2, 3]))
|
|
self.assertEqual([mock(), mock(), mock()], [1, 2, 3])
|
|
self.assertRaises(StopIteration, mock)
|
|
|
|
mock = MagicMock(side_effect=['a', 'b', 'c'])
|
|
self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c'])
|
|
self.assertRaises(StopIteration, mock)
|
|
|
|
mock = Mock(side_effect='ghi')
|
|
self.assertEqual([mock(), mock(), mock()], ['g', 'h', 'i'])
|
|
self.assertRaises(StopIteration, mock)
|
|
|
|
class Foo(object):
|
|
pass
|
|
mock = MagicMock(side_effect=Foo)
|
|
self.assertIsInstance(mock(), Foo)
|
|
|
|
mock = Mock(side_effect=Iter())
|
|
self.assertEqual([mock(), mock(), mock(), mock()],
|
|
['this', 'is', 'an', 'iter'])
|
|
self.assertRaises(StopIteration, mock)
|
|
|
|
|
|
def test_side_effect_iterator_exceptions(self):
|
|
for Klass in Mock, MagicMock:
|
|
iterable = (ValueError, 3, KeyError, 6)
|
|
m = Klass(side_effect=iterable)
|
|
self.assertRaises(ValueError, m)
|
|
self.assertEqual(m(), 3)
|
|
self.assertRaises(KeyError, m)
|
|
self.assertEqual(m(), 6)
|
|
|
|
|
|
def test_side_effect_setting_iterator(self):
|
|
mock = Mock()
|
|
mock.side_effect = iter([1, 2, 3])
|
|
self.assertEqual([mock(), mock(), mock()], [1, 2, 3])
|
|
self.assertRaises(StopIteration, mock)
|
|
side_effect = mock.side_effect
|
|
self.assertIsInstance(side_effect, type(iter([])))
|
|
|
|
mock.side_effect = ['a', 'b', 'c']
|
|
self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c'])
|
|
self.assertRaises(StopIteration, mock)
|
|
side_effect = mock.side_effect
|
|
self.assertIsInstance(side_effect, type(iter([])))
|
|
|
|
this_iter = Iter()
|
|
mock.side_effect = this_iter
|
|
self.assertEqual([mock(), mock(), mock(), mock()],
|
|
['this', 'is', 'an', 'iter'])
|
|
self.assertRaises(StopIteration, mock)
|
|
self.assertIs(mock.side_effect, this_iter)
|
|
|
|
def test_side_effect_iterator_default(self):
|
|
mock = Mock(return_value=2)
|
|
mock.side_effect = iter([1, DEFAULT])
|
|
self.assertEqual([mock(), mock()], [1, 2])
|
|
|
|
def test_assert_has_calls_any_order(self):
|
|
mock = Mock()
|
|
mock(1, 2)
|
|
mock(a=3)
|
|
mock(3, 4)
|
|
mock(b=6)
|
|
mock(b=6)
|
|
|
|
kalls = [
|
|
call(1, 2), ({'a': 3},),
|
|
((3, 4),), ((), {'a': 3}),
|
|
('', (1, 2)), ('', {'a': 3}),
|
|
('', (1, 2), {}), ('', (), {'a': 3})
|
|
]
|
|
for kall in kalls:
|
|
mock.assert_has_calls([kall], any_order=True)
|
|
|
|
for kall in call(1, '2'), call(b=3), call(), 3, None, 'foo':
|
|
self.assertRaises(
|
|
AssertionError, mock.assert_has_calls,
|
|
[kall], any_order=True
|
|
)
|
|
|
|
kall_lists = [
|
|
[call(1, 2), call(b=6)],
|
|
[call(3, 4), call(1, 2)],
|
|
[call(b=6), call(b=6)],
|
|
]
|
|
|
|
for kall_list in kall_lists:
|
|
mock.assert_has_calls(kall_list, any_order=True)
|
|
|
|
kall_lists = [
|
|
[call(b=6), call(b=6), call(b=6)],
|
|
[call(1, 2), call(1, 2)],
|
|
[call(3, 4), call(1, 2), call(5, 7)],
|
|
[call(b=6), call(3, 4), call(b=6), call(1, 2), call(b=6)],
|
|
]
|
|
for kall_list in kall_lists:
|
|
self.assertRaises(
|
|
AssertionError, mock.assert_has_calls,
|
|
kall_list, any_order=True
|
|
)
|
|
|
|
def test_assert_has_calls(self):
|
|
kalls1 = [
|
|
call(1, 2), ({'a': 3},),
|
|
((3, 4),), call(b=6),
|
|
('', (1,), {'b': 6}),
|
|
]
|
|
kalls2 = [call.foo(), call.bar(1)]
|
|
kalls2.extend(call.spam().baz(a=3).call_list())
|
|
kalls2.extend(call.bam(set(), foo={}).fish([1]).call_list())
|
|
|
|
mocks = []
|
|
for mock in Mock(), MagicMock():
|
|
mock(1, 2)
|
|
mock(a=3)
|
|
mock(3, 4)
|
|
mock(b=6)
|
|
mock(1, b=6)
|
|
mocks.append((mock, kalls1))
|
|
|
|
mock = Mock()
|
|
mock.foo()
|
|
mock.bar(1)
|
|
mock.spam().baz(a=3)
|
|
mock.bam(set(), foo={}).fish([1])
|
|
mocks.append((mock, kalls2))
|
|
|
|
for mock, kalls in mocks:
|
|
for i in range(len(kalls)):
|
|
for step in 1, 2, 3:
|
|
these = kalls[i:i+step]
|
|
mock.assert_has_calls(these)
|
|
|
|
if len(these) > 1:
|
|
self.assertRaises(
|
|
AssertionError,
|
|
mock.assert_has_calls,
|
|
list(reversed(these))
|
|
)
|
|
|
|
|
|
def test_assert_has_calls_nested_spec(self):
|
|
class Something:
|
|
|
|
def __init__(self): pass
|
|
def meth(self, a, b, c, d=None): pass
|
|
|
|
class Foo:
|
|
|
|
def __init__(self, a): pass
|
|
def meth1(self, a, b): pass
|
|
|
|
mock_class = create_autospec(Something)
|
|
|
|
for m in [mock_class, mock_class()]:
|
|
m.meth(1, 2, 3, d=1)
|
|
m.assert_has_calls([call.meth(1, 2, 3, d=1)])
|
|
m.assert_has_calls([call.meth(1, 2, 3, 1)])
|
|
|
|
mock_class.reset_mock()
|
|
|
|
for m in [mock_class, mock_class()]:
|
|
self.assertRaises(AssertionError, m.assert_has_calls, [call.Foo()])
|
|
m.Foo(1).meth1(1, 2)
|
|
m.assert_has_calls([call.Foo(1), call.Foo(1).meth1(1, 2)])
|
|
m.Foo.assert_has_calls([call(1), call().meth1(1, 2)])
|
|
|
|
mock_class.reset_mock()
|
|
|
|
invalid_calls = [call.meth(1),
|
|
call.non_existent(1),
|
|
call.Foo().non_existent(1),
|
|
call.Foo().meth(1, 2, 3, 4)]
|
|
|
|
for kall in invalid_calls:
|
|
self.assertRaises(AssertionError,
|
|
mock_class.assert_has_calls,
|
|
[kall]
|
|
)
|
|
|
|
|
|
def test_assert_has_calls_nested_without_spec(self):
|
|
m = MagicMock()
|
|
m().foo().bar().baz()
|
|
m.one().two().three()
|
|
calls = call.one().two().three().call_list()
|
|
m.assert_has_calls(calls)
|
|
|
|
|
|
def test_assert_has_calls_with_function_spec(self):
|
|
def f(a, b, c, d=None): pass
|
|
|
|
mock = Mock(spec=f)
|
|
|
|
mock(1, b=2, c=3)
|
|
mock(4, 5, c=6, d=7)
|
|
mock(10, 11, c=12)
|
|
calls = [
|
|
('', (1, 2, 3), {}),
|
|
('', (4, 5, 6), {'d': 7}),
|
|
((10, 11, 12), {}),
|
|
]
|
|
mock.assert_has_calls(calls)
|
|
mock.assert_has_calls(calls, any_order=True)
|
|
mock.assert_has_calls(calls[1:])
|
|
mock.assert_has_calls(calls[1:], any_order=True)
|
|
mock.assert_has_calls(calls[:-1])
|
|
mock.assert_has_calls(calls[:-1], any_order=True)
|
|
# Reversed order
|
|
calls = list(reversed(calls))
|
|
with self.assertRaises(AssertionError):
|
|
mock.assert_has_calls(calls)
|
|
mock.assert_has_calls(calls, any_order=True)
|
|
with self.assertRaises(AssertionError):
|
|
mock.assert_has_calls(calls[1:])
|
|
mock.assert_has_calls(calls[1:], any_order=True)
|
|
with self.assertRaises(AssertionError):
|
|
mock.assert_has_calls(calls[:-1])
|
|
mock.assert_has_calls(calls[:-1], any_order=True)
|
|
|
|
def test_assert_has_calls_not_matching_spec_error(self):
|
|
def f(x=None): pass
|
|
|
|
mock = Mock(spec=f)
|
|
mock(1)
|
|
|
|
with self.assertRaisesRegex(
|
|
AssertionError,
|
|
'^{}$'.format(
|
|
re.escape('Calls not found.\n'
|
|
'Expected: [call()]\n'
|
|
'Actual: [call(1)]'))) as cm:
|
|
mock.assert_has_calls([call()])
|
|
self.assertIsNone(cm.exception.__cause__)
|
|
|
|
|
|
with self.assertRaisesRegex(
|
|
AssertionError,
|
|
'^{}$'.format(
|
|
re.escape(
|
|
'Error processing expected calls.\n'
|
|
"Errors: [None, TypeError('too many positional arguments')]\n"
|
|
"Expected: [call(), call(1, 2)]\n"
|
|
'Actual: [call(1)]'))) as cm:
|
|
mock.assert_has_calls([call(), call(1, 2)])
|
|
self.assertIsInstance(cm.exception.__cause__, TypeError)
|
|
|
|
def test_assert_any_call(self):
|
|
mock = Mock()
|
|
mock(1, 2)
|
|
mock(a=3)
|
|
mock(1, b=6)
|
|
|
|
mock.assert_any_call(1, 2)
|
|
mock.assert_any_call(a=3)
|
|
mock.assert_any_call(1, b=6)
|
|
|
|
self.assertRaises(
|
|
AssertionError,
|
|
mock.assert_any_call
|
|
)
|
|
self.assertRaises(
|
|
AssertionError,
|
|
mock.assert_any_call,
|
|
1, 3
|
|
)
|
|
self.assertRaises(
|
|
AssertionError,
|
|
mock.assert_any_call,
|
|
a=4
|
|
)
|
|
|
|
|
|
def test_assert_any_call_with_function_spec(self):
|
|
def f(a, b, c, d=None): pass
|
|
|
|
mock = Mock(spec=f)
|
|
|
|
mock(1, b=2, c=3)
|
|
mock(4, 5, c=6, d=7)
|
|
mock.assert_any_call(1, 2, 3)
|
|
mock.assert_any_call(a=1, b=2, c=3)
|
|
mock.assert_any_call(4, 5, 6, 7)
|
|
mock.assert_any_call(a=4, b=5, c=6, d=7)
|
|
self.assertRaises(AssertionError, mock.assert_any_call,
|
|
1, b=3, c=2)
|
|
# Expected call doesn't match the spec's signature
|
|
with self.assertRaises(AssertionError) as cm:
|
|
mock.assert_any_call(e=8)
|
|
self.assertIsInstance(cm.exception.__cause__, TypeError)
|
|
|
|
|
|
def test_mock_calls_create_autospec(self):
|
|
def f(a, b): pass
|
|
obj = Iter()
|
|
obj.f = f
|
|
|
|
funcs = [
|
|
create_autospec(f),
|
|
create_autospec(obj).f
|
|
]
|
|
for func in funcs:
|
|
func(1, 2)
|
|
func(3, 4)
|
|
|
|
self.assertEqual(
|
|
func.mock_calls, [call(1, 2), call(3, 4)]
|
|
)
|
|
|
|
#Issue21222
|
|
def test_create_autospec_with_name(self):
|
|
m = mock.create_autospec(object(), name='sweet_func')
|
|
self.assertIn('sweet_func', repr(m))
|
|
|
|
#Issue23078
|
|
def test_create_autospec_classmethod_and_staticmethod(self):
|
|
class TestClass:
|
|
@classmethod
|
|
def class_method(cls): pass
|
|
|
|
@staticmethod
|
|
def static_method(): pass
|
|
for method in ('class_method', 'static_method'):
|
|
with self.subTest(method=method):
|
|
mock_method = mock.create_autospec(getattr(TestClass, method))
|
|
mock_method()
|
|
mock_method.assert_called_once_with()
|
|
self.assertRaises(TypeError, mock_method, 'extra_arg')
|
|
|
|
#Issue21238
|
|
def test_mock_unsafe(self):
|
|
m = Mock()
|
|
msg = "is not a valid assertion. Use a spec for the mock"
|
|
with self.assertRaisesRegex(AttributeError, msg):
|
|
m.assert_foo_call()
|
|
with self.assertRaisesRegex(AttributeError, msg):
|
|
m.assret_foo_call()
|
|
with self.assertRaisesRegex(AttributeError, msg):
|
|
m.asert_foo_call()
|
|
with self.assertRaisesRegex(AttributeError, msg):
|
|
m.aseert_foo_call()
|
|
with self.assertRaisesRegex(AttributeError, msg):
|
|
m.assrt_foo_call()
|
|
m = Mock(unsafe=True)
|
|
m.assert_foo_call()
|
|
m.assret_foo_call()
|
|
m.asert_foo_call()
|
|
m.aseert_foo_call()
|
|
m.assrt_foo_call()
|
|
|
|
#Issue21262
|
|
def test_assert_not_called(self):
|
|
m = Mock()
|
|
m.hello.assert_not_called()
|
|
m.hello()
|
|
with self.assertRaises(AssertionError):
|
|
m.hello.assert_not_called()
|
|
|
|
def test_assert_not_called_message(self):
|
|
m = Mock()
|
|
m(1, 2)
|
|
self.assertRaisesRegex(AssertionError,
|
|
re.escape("Calls: [call(1, 2)]"),
|
|
m.assert_not_called)
|
|
|
|
def test_assert_called(self):
|
|
m = Mock()
|
|
with self.assertRaises(AssertionError):
|
|
m.hello.assert_called()
|
|
m.hello()
|
|
m.hello.assert_called()
|
|
|
|
m.hello()
|
|
m.hello.assert_called()
|
|
|
|
def test_assert_called_once(self):
|
|
m = Mock()
|
|
with self.assertRaises(AssertionError):
|
|
m.hello.assert_called_once()
|
|
m.hello()
|
|
m.hello.assert_called_once()
|
|
|
|
m.hello()
|
|
with self.assertRaises(AssertionError):
|
|
m.hello.assert_called_once()
|
|
|
|
def test_assert_called_once_message(self):
|
|
m = Mock()
|
|
m(1, 2)
|
|
m(3)
|
|
self.assertRaisesRegex(AssertionError,
|
|
re.escape("Calls: [call(1, 2), call(3)]"),
|
|
m.assert_called_once)
|
|
|
|
def test_assert_called_once_message_not_called(self):
|
|
m = Mock()
|
|
with self.assertRaises(AssertionError) as e:
|
|
m.assert_called_once()
|
|
self.assertNotIn("Calls:", str(e.exception))
|
|
|
|
#Issue37212 printout of keyword args now preserves the original order
|
|
def test_ordered_call_signature(self):
|
|
m = Mock()
|
|
m.hello(name='hello', daddy='hero')
|
|
text = "call(name='hello', daddy='hero')"
|
|
self.assertEqual(repr(m.hello.call_args), text)
|
|
|
|
#Issue21270 overrides tuple methods for mock.call objects
|
|
def test_override_tuple_methods(self):
|
|
c = call.count()
|
|
i = call.index(132,'hello')
|
|
m = Mock()
|
|
m.count()
|
|
m.index(132,"hello")
|
|
self.assertEqual(m.method_calls[0], c)
|
|
self.assertEqual(m.method_calls[1], i)
|
|
|
|
def test_reset_return_sideeffect(self):
|
|
m = Mock(return_value=10, side_effect=[2,3])
|
|
m.reset_mock(return_value=True, side_effect=True)
|
|
self.assertIsInstance(m.return_value, Mock)
|
|
self.assertEqual(m.side_effect, None)
|
|
|
|
def test_reset_return(self):
|
|
m = Mock(return_value=10, side_effect=[2,3])
|
|
m.reset_mock(return_value=True)
|
|
self.assertIsInstance(m.return_value, Mock)
|
|
self.assertNotEqual(m.side_effect, None)
|
|
|
|
def test_reset_sideeffect(self):
|
|
m = Mock(return_value=10, side_effect=[2, 3])
|
|
m.reset_mock(side_effect=True)
|
|
self.assertEqual(m.return_value, 10)
|
|
self.assertEqual(m.side_effect, None)
|
|
|
|
def test_reset_return_with_children(self):
|
|
m = MagicMock(f=MagicMock(return_value=1))
|
|
self.assertEqual(m.f(), 1)
|
|
m.reset_mock(return_value=True)
|
|
self.assertNotEqual(m.f(), 1)
|
|
|
|
def test_reset_return_with_children_side_effect(self):
|
|
m = MagicMock(f=MagicMock(side_effect=[2, 3]))
|
|
self.assertNotEqual(m.f.side_effect, None)
|
|
m.reset_mock(side_effect=True)
|
|
self.assertEqual(m.f.side_effect, None)
|
|
|
|
def test_mock_add_spec(self):
|
|
class _One(object):
|
|
one = 1
|
|
class _Two(object):
|
|
two = 2
|
|
class Anything(object):
|
|
one = two = three = 'four'
|
|
|
|
klasses = [
|
|
Mock, MagicMock, NonCallableMock, NonCallableMagicMock
|
|
]
|
|
for Klass in list(klasses):
|
|
klasses.append(lambda K=Klass: K(spec=Anything))
|
|
klasses.append(lambda K=Klass: K(spec_set=Anything))
|
|
|
|
for Klass in klasses:
|
|
for kwargs in dict(), dict(spec_set=True):
|
|
mock = Klass()
|
|
#no error
|
|
mock.one, mock.two, mock.three
|
|
|
|
for One, Two in [(_One, _Two), (['one'], ['two'])]:
|
|
for kwargs in dict(), dict(spec_set=True):
|
|
mock.mock_add_spec(One, **kwargs)
|
|
|
|
mock.one
|
|
self.assertRaises(
|
|
AttributeError, getattr, mock, 'two'
|
|
)
|
|
self.assertRaises(
|
|
AttributeError, getattr, mock, 'three'
|
|
)
|
|
if 'spec_set' in kwargs:
|
|
self.assertRaises(
|
|
AttributeError, setattr, mock, 'three', None
|
|
)
|
|
|
|
mock.mock_add_spec(Two, **kwargs)
|
|
self.assertRaises(
|
|
AttributeError, getattr, mock, 'one'
|
|
)
|
|
mock.two
|
|
self.assertRaises(
|
|
AttributeError, getattr, mock, 'three'
|
|
)
|
|
if 'spec_set' in kwargs:
|
|
self.assertRaises(
|
|
AttributeError, setattr, mock, 'three', None
|
|
)
|
|
# note that creating a mock, setting an instance attribute, and
|
|
# *then* setting a spec doesn't work. Not the intended use case
|
|
|
|
|
|
def test_mock_add_spec_magic_methods(self):
|
|
for Klass in MagicMock, NonCallableMagicMock:
|
|
mock = Klass()
|
|
int(mock)
|
|
|
|
mock.mock_add_spec(object)
|
|
self.assertRaises(TypeError, int, mock)
|
|
|
|
mock = Klass()
|
|
mock['foo']
|
|
mock.__int__.return_value =4
|
|
|
|
mock.mock_add_spec(int)
|
|
self.assertEqual(int(mock), 4)
|
|
self.assertRaises(TypeError, lambda: mock['foo'])
|
|
|
|
|
|
def test_adding_child_mock(self):
|
|
for Klass in (NonCallableMock, Mock, MagicMock, NonCallableMagicMock,
|
|
AsyncMock):
|
|
mock = Klass()
|
|
|
|
mock.foo = Mock()
|
|
mock.foo()
|
|
|
|
self.assertEqual(mock.method_calls, [call.foo()])
|
|
self.assertEqual(mock.mock_calls, [call.foo()])
|
|
|
|
mock = Klass()
|
|
mock.bar = Mock(name='name')
|
|
mock.bar()
|
|
self.assertEqual(mock.method_calls, [])
|
|
self.assertEqual(mock.mock_calls, [])
|
|
|
|
# mock with an existing _new_parent but no name
|
|
mock = Klass()
|
|
mock.baz = MagicMock()()
|
|
mock.baz()
|
|
self.assertEqual(mock.method_calls, [])
|
|
self.assertEqual(mock.mock_calls, [])
|
|
|
|
|
|
def test_adding_return_value_mock(self):
|
|
for Klass in Mock, MagicMock:
|
|
mock = Klass()
|
|
mock.return_value = MagicMock()
|
|
|
|
mock()()
|
|
self.assertEqual(mock.mock_calls, [call(), call()()])
|
|
|
|
|
|
def test_manager_mock(self):
|
|
class Foo(object):
|
|
one = 'one'
|
|
two = 'two'
|
|
manager = Mock()
|
|
p1 = patch.object(Foo, 'one')
|
|
p2 = patch.object(Foo, 'two')
|
|
|
|
mock_one = p1.start()
|
|
self.addCleanup(p1.stop)
|
|
mock_two = p2.start()
|
|
self.addCleanup(p2.stop)
|
|
|
|
manager.attach_mock(mock_one, 'one')
|
|
manager.attach_mock(mock_two, 'two')
|
|
|
|
Foo.two()
|
|
Foo.one()
|
|
|
|
self.assertEqual(manager.mock_calls, [call.two(), call.one()])
|
|
|
|
|
|
def test_magic_methods_mock_calls(self):
|
|
for Klass in Mock, MagicMock:
|
|
m = Klass()
|
|
m.__int__ = Mock(return_value=3)
|
|
m.__float__ = MagicMock(return_value=3.0)
|
|
int(m)
|
|
float(m)
|
|
|
|
self.assertEqual(m.mock_calls, [call.__int__(), call.__float__()])
|
|
self.assertEqual(m.method_calls, [])
|
|
|
|
def test_mock_open_reuse_issue_21750(self):
|
|
mocked_open = mock.mock_open(read_data='data')
|
|
f1 = mocked_open('a-name')
|
|
f1_data = f1.read()
|
|
f2 = mocked_open('another-name')
|
|
f2_data = f2.read()
|
|
self.assertEqual(f1_data, f2_data)
|
|
|
|
def test_mock_open_dunder_iter_issue(self):
|
|
# Test dunder_iter method generates the expected result and
|
|
# consumes the iterator.
|
|
mocked_open = mock.mock_open(read_data='Remarkable\nNorwegian Blue')
|
|
f1 = mocked_open('a-name')
|
|
lines = [line for line in f1]
|
|
self.assertEqual(lines[0], 'Remarkable\n')
|
|
self.assertEqual(lines[1], 'Norwegian Blue')
|
|
self.assertEqual(list(f1), [])
|
|
|
|
def test_mock_open_using_next(self):
|
|
mocked_open = mock.mock_open(read_data='1st line\n2nd line\n3rd line')
|
|
f1 = mocked_open('a-name')
|
|
line1 = next(f1)
|
|
line2 = f1.__next__()
|
|
lines = [line for line in f1]
|
|
self.assertEqual(line1, '1st line\n')
|
|
self.assertEqual(line2, '2nd line\n')
|
|
self.assertEqual(lines[0], '3rd line')
|
|
self.assertEqual(list(f1), [])
|
|
with self.assertRaises(StopIteration):
|
|
next(f1)
|
|
|
|
def test_mock_open_next_with_readline_with_return_value(self):
|
|
mopen = mock.mock_open(read_data='foo\nbarn')
|
|
mopen.return_value.readline.return_value = 'abc'
|
|
self.assertEqual('abc', next(mopen()))
|
|
|
|
def test_mock_open_write(self):
|
|
# Test exception in file writing write()
|
|
mock_namedtemp = mock.mock_open(mock.MagicMock(name='JLV'))
|
|
with mock.patch('tempfile.NamedTemporaryFile', mock_namedtemp):
|
|
mock_filehandle = mock_namedtemp.return_value
|
|
mock_write = mock_filehandle.write
|
|
mock_write.side_effect = OSError('Test 2 Error')
|
|
def attempt():
|
|
tempfile.NamedTemporaryFile().write('asd')
|
|
self.assertRaises(OSError, attempt)
|
|
|
|
def test_mock_open_alter_readline(self):
|
|
mopen = mock.mock_open(read_data='foo\nbarn')
|
|
mopen.return_value.readline.side_effect = lambda *args:'abc'
|
|
first = mopen().readline()
|
|
second = mopen().readline()
|
|
self.assertEqual('abc', first)
|
|
self.assertEqual('abc', second)
|
|
|
|
def test_mock_open_after_eof(self):
|
|
# read, readline and readlines should work after end of file.
|
|
_open = mock.mock_open(read_data='foo')
|
|
h = _open('bar')
|
|
h.read()
|
|
self.assertEqual('', h.read())
|
|
self.assertEqual('', h.read())
|
|
self.assertEqual('', h.readline())
|
|
self.assertEqual('', h.readline())
|
|
self.assertEqual([], h.readlines())
|
|
self.assertEqual([], h.readlines())
|
|
|
|
def test_mock_parents(self):
|
|
for Klass in Mock, MagicMock:
|
|
m = Klass()
|
|
original_repr = repr(m)
|
|
m.return_value = m
|
|
self.assertIs(m(), m)
|
|
self.assertEqual(repr(m), original_repr)
|
|
|
|
m.reset_mock()
|
|
self.assertIs(m(), m)
|
|
self.assertEqual(repr(m), original_repr)
|
|
|
|
m = Klass()
|
|
m.b = m.a
|
|
self.assertIn("name='mock.a'", repr(m.b))
|
|
self.assertIn("name='mock.a'", repr(m.a))
|
|
m.reset_mock()
|
|
self.assertIn("name='mock.a'", repr(m.b))
|
|
self.assertIn("name='mock.a'", repr(m.a))
|
|
|
|
m = Klass()
|
|
original_repr = repr(m)
|
|
m.a = m()
|
|
m.a.return_value = m
|
|
|
|
self.assertEqual(repr(m), original_repr)
|
|
self.assertEqual(repr(m.a()), original_repr)
|
|
|
|
|
|
def test_attach_mock(self):
|
|
classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock
|
|
for Klass in classes:
|
|
for Klass2 in classes:
|
|
m = Klass()
|
|
|
|
m2 = Klass2(name='foo')
|
|
m.attach_mock(m2, 'bar')
|
|
|
|
self.assertIs(m.bar, m2)
|
|
self.assertIn("name='mock.bar'", repr(m2))
|
|
|
|
m.bar.baz(1)
|
|
self.assertEqual(m.mock_calls, [call.bar.baz(1)])
|
|
self.assertEqual(m.method_calls, [call.bar.baz(1)])
|
|
|
|
|
|
def test_attach_mock_return_value(self):
|
|
classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock
|
|
for Klass in Mock, MagicMock:
|
|
for Klass2 in classes:
|
|
m = Klass()
|
|
|
|
m2 = Klass2(name='foo')
|
|
m.attach_mock(m2, 'return_value')
|
|
|
|
self.assertIs(m(), m2)
|
|
self.assertIn("name='mock()'", repr(m2))
|
|
|
|
m2.foo()
|
|
self.assertEqual(m.mock_calls, call().foo().call_list())
|
|
|
|
|
|
def test_attach_mock_patch_autospec(self):
|
|
parent = Mock()
|
|
|
|
with mock.patch(f'{__name__}.something', autospec=True) as mock_func:
|
|
self.assertEqual(mock_func.mock._extract_mock_name(), 'something')
|
|
parent.attach_mock(mock_func, 'child')
|
|
parent.child(1)
|
|
something(2)
|
|
mock_func(3)
|
|
|
|
parent_calls = [call.child(1), call.child(2), call.child(3)]
|
|
child_calls = [call(1), call(2), call(3)]
|
|
self.assertEqual(parent.mock_calls, parent_calls)
|
|
self.assertEqual(parent.child.mock_calls, child_calls)
|
|
self.assertEqual(something.mock_calls, child_calls)
|
|
self.assertEqual(mock_func.mock_calls, child_calls)
|
|
self.assertIn('mock.child', repr(parent.child.mock))
|
|
self.assertEqual(mock_func.mock._extract_mock_name(), 'mock.child')
|
|
|
|
|
|
def test_attach_mock_patch_autospec_signature(self):
|
|
with mock.patch(f'{__name__}.Something.meth', autospec=True) as mocked:
|
|
manager = Mock()
|
|
manager.attach_mock(mocked, 'attach_meth')
|
|
obj = Something()
|
|
obj.meth(1, 2, 3, d=4)
|
|
manager.assert_has_calls([call.attach_meth(mock.ANY, 1, 2, 3, d=4)])
|
|
obj.meth.assert_has_calls([call(mock.ANY, 1, 2, 3, d=4)])
|
|
mocked.assert_has_calls([call(mock.ANY, 1, 2, 3, d=4)])
|
|
|
|
with mock.patch(f'{__name__}.something', autospec=True) as mocked:
|
|
manager = Mock()
|
|
manager.attach_mock(mocked, 'attach_func')
|
|
something(1)
|
|
manager.assert_has_calls([call.attach_func(1)])
|
|
something.assert_has_calls([call(1)])
|
|
mocked.assert_has_calls([call(1)])
|
|
|
|
with mock.patch(f'{__name__}.Something', autospec=True) as mocked:
|
|
manager = Mock()
|
|
manager.attach_mock(mocked, 'attach_obj')
|
|
obj = Something()
|
|
obj.meth(1, 2, 3, d=4)
|
|
manager.assert_has_calls([call.attach_obj(),
|
|
call.attach_obj().meth(1, 2, 3, d=4)])
|
|
obj.meth.assert_has_calls([call(1, 2, 3, d=4)])
|
|
mocked.assert_has_calls([call(), call().meth(1, 2, 3, d=4)])
|
|
|
|
|
|
def test_attribute_deletion(self):
|
|
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
|
|
NonCallableMock()):
|
|
self.assertTrue(hasattr(mock, 'm'))
|
|
|
|
del mock.m
|
|
self.assertFalse(hasattr(mock, 'm'))
|
|
|
|
del mock.f
|
|
self.assertFalse(hasattr(mock, 'f'))
|
|
self.assertRaises(AttributeError, getattr, mock, 'f')
|
|
|
|
|
|
def test_mock_does_not_raise_on_repeated_attribute_deletion(self):
|
|
# bpo-20239: Assigning and deleting twice an attribute raises.
|
|
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
|
|
NonCallableMock()):
|
|
mock.foo = 3
|
|
self.assertTrue(hasattr(mock, 'foo'))
|
|
self.assertEqual(mock.foo, 3)
|
|
|
|
del mock.foo
|
|
self.assertFalse(hasattr(mock, 'foo'))
|
|
|
|
mock.foo = 4
|
|
self.assertTrue(hasattr(mock, 'foo'))
|
|
self.assertEqual(mock.foo, 4)
|
|
|
|
del mock.foo
|
|
self.assertFalse(hasattr(mock, 'foo'))
|
|
|
|
|
|
def test_mock_raises_when_deleting_nonexistent_attribute(self):
|
|
for mock in (Mock(), MagicMock(), NonCallableMagicMock(),
|
|
NonCallableMock()):
|
|
del mock.foo
|
|
with self.assertRaises(AttributeError):
|
|
del mock.foo
|
|
|
|
|
|
def test_reset_mock_does_not_raise_on_attr_deletion(self):
|
|
# bpo-31177: reset_mock should not raise AttributeError when attributes
|
|
# were deleted in a mock instance
|
|
mock = Mock()
|
|
mock.child = True
|
|
del mock.child
|
|
mock.reset_mock()
|
|
self.assertFalse(hasattr(mock, 'child'))
|
|
|
|
|
|
def test_class_assignable(self):
|
|
for mock in Mock(), MagicMock():
|
|
self.assertNotIsInstance(mock, int)
|
|
|
|
mock.__class__ = int
|
|
self.assertIsInstance(mock, int)
|
|
mock.foo
|
|
|
|
def test_name_attribute_of_call(self):
|
|
# bpo-35357: _Call should not disclose any attributes whose names
|
|
# may clash with popular ones (such as ".name")
|
|
self.assertIsNotNone(call.name)
|
|
self.assertEqual(type(call.name), _Call)
|
|
self.assertEqual(type(call.name().name), _Call)
|
|
|
|
def test_parent_attribute_of_call(self):
|
|
# bpo-35357: _Call should not disclose any attributes whose names
|
|
# may clash with popular ones (such as ".parent")
|
|
self.assertIsNotNone(call.parent)
|
|
self.assertEqual(type(call.parent), _Call)
|
|
self.assertEqual(type(call.parent().parent), _Call)
|
|
|
|
|
|
def test_parent_propagation_with_create_autospec(self):
|
|
|
|
def foo(a, b): pass
|
|
|
|
mock = Mock()
|
|
mock.child = create_autospec(foo)
|
|
mock.child(1, 2)
|
|
|
|
self.assertRaises(TypeError, mock.child, 1)
|
|
self.assertEqual(mock.mock_calls, [call.child(1, 2)])
|
|
self.assertIn('mock.child', repr(mock.child.mock))
|
|
|
|
def test_parent_propagation_with_autospec_attach_mock(self):
|
|
|
|
def foo(a, b): pass
|
|
|
|
parent = Mock()
|
|
parent.attach_mock(create_autospec(foo, name='bar'), 'child')
|
|
parent.child(1, 2)
|
|
|
|
self.assertRaises(TypeError, parent.child, 1)
|
|
self.assertEqual(parent.child.mock_calls, [call.child(1, 2)])
|
|
self.assertIn('mock.child', repr(parent.child.mock))
|
|
|
|
|
|
def test_isinstance_under_settrace(self):
|
|
# bpo-36593 : __class__ is not set for a class that has __class__
|
|
# property defined when it's used with sys.settrace(trace) set.
|
|
# Delete the module to force reimport with tracing function set
|
|
# restore the old reference later since there are other tests that are
|
|
# dependent on unittest.mock.patch. In testpatch.PatchTest
|
|
# test_patch_dict_test_prefix and test_patch_test_prefix not restoring
|
|
# causes the objects patched to go out of sync
|
|
|
|
old_patch = unittest.mock.patch
|
|
|
|
# Directly using __setattr__ on unittest.mock causes current imported
|
|
# reference to be updated. Use a lambda so that during cleanup the
|
|
# re-imported new reference is updated.
|
|
self.addCleanup(lambda patch: setattr(unittest.mock, 'patch', patch),
|
|
old_patch)
|
|
|
|
with patch.dict('sys.modules'):
|
|
del sys.modules['unittest.mock']
|
|
|
|
# This trace will stop coverage being measured ;-)
|
|
def trace(frame, event, arg): # pragma: no cover
|
|
return trace
|
|
|
|
self.addCleanup(sys.settrace, sys.gettrace())
|
|
sys.settrace(trace)
|
|
|
|
from unittest.mock import (
|
|
Mock, MagicMock, NonCallableMock, NonCallableMagicMock
|
|
)
|
|
|
|
mocks = [
|
|
Mock, MagicMock, NonCallableMock, NonCallableMagicMock, AsyncMock
|
|
]
|
|
|
|
for mock in mocks:
|
|
obj = mock(spec=Something)
|
|
self.assertIsInstance(obj, Something)
|
|
|
|
def test_bool_not_called_when_passing_spec_arg(self):
|
|
class Something:
|
|
def __init__(self):
|
|
self.obj_with_bool_func = unittest.mock.MagicMock()
|
|
|
|
obj = Something()
|
|
with unittest.mock.patch.object(obj, 'obj_with_bool_func', autospec=True): pass
|
|
|
|
self.assertEqual(obj.obj_with_bool_func.__bool__.call_count, 0)
|
|
|
|
def test_misspelled_arguments(self):
|
|
class Foo():
|
|
one = 'one'
|
|
# patch, patch.object and create_autospec need to check for misspelled
|
|
# arguments explicitly and throw a RuntimError if found.
|
|
with self.assertRaises(RuntimeError):
|
|
with patch(f'{__name__}.Something.meth', autospect=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
with patch.object(Foo, 'one', autospect=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
with patch(f'{__name__}.Something.meth', auto_spec=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
with patch.object(Foo, 'one', auto_spec=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
with patch(f'{__name__}.Something.meth', set_spec=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
with patch.object(Foo, 'one', set_spec=True): pass
|
|
with self.assertRaises(RuntimeError):
|
|
m = create_autospec(Foo, set_spec=True)
|
|
# patch.multiple, on the other hand, should flag misspelled arguments
|
|
# through an AttributeError, when trying to find the keys from kwargs
|
|
# as attributes on the target.
|
|
with self.assertRaises(AttributeError):
|
|
with patch.multiple(
|
|
f'{__name__}.Something', meth=DEFAULT, autospect=True): pass
|
|
with self.assertRaises(AttributeError):
|
|
with patch.multiple(
|
|
f'{__name__}.Something', meth=DEFAULT, auto_spec=True): pass
|
|
with self.assertRaises(AttributeError):
|
|
with patch.multiple(
|
|
f'{__name__}.Something', meth=DEFAULT, set_spec=True): pass
|
|
|
|
with patch(f'{__name__}.Something.meth', unsafe=True, autospect=True):
|
|
pass
|
|
with patch.object(Foo, 'one', unsafe=True, autospect=True): pass
|
|
with patch(f'{__name__}.Something.meth', unsafe=True, auto_spec=True):
|
|
pass
|
|
with patch.object(Foo, 'one', unsafe=True, auto_spec=True): pass
|
|
with patch(f'{__name__}.Something.meth', unsafe=True, set_spec=True):
|
|
pass
|
|
with patch.object(Foo, 'one', unsafe=True, set_spec=True): pass
|
|
m = create_autospec(Foo, set_spec=True, unsafe=True)
|
|
with patch.multiple(
|
|
f'{__name__}.Typos', autospect=True, set_spec=True, auto_spec=True):
|
|
pass
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|