119 lines
4.4 KiB
Python
119 lines
4.4 KiB
Python
# Copyright 2017 Cloudbase Solutions Srl
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import testtools
|
|
from unittest import mock
|
|
|
|
from oslotest import mock_fixture
|
|
|
|
# NOTE(claudiub): this needs to be called before any mock.patch calls are
|
|
# being done, and especially before the test class loads. This fixes
|
|
# the mock.patch autospec issue:
|
|
# https://github.com/testing-cabal/mock/issues/396
|
|
# TODO(claudiub): Remove this once the fix has been merged and released.
|
|
mock_fixture.patch_mock_module()
|
|
|
|
|
|
class Foo(object):
|
|
def bar(self, a, b, c, d=None):
|
|
pass
|
|
|
|
@classmethod
|
|
def classic_bar(cls, a, b, c, d=None):
|
|
pass
|
|
|
|
@staticmethod
|
|
def static_bar(a, b, c, d=None):
|
|
pass
|
|
|
|
|
|
class MockSanityTestCase(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(MockSanityTestCase, self).setUp()
|
|
self.useFixture(mock_fixture.MockAutospecFixture())
|
|
|
|
def _check_autospeced_foo(self, foo):
|
|
for method_name in ['bar', 'classic_bar', 'static_bar']:
|
|
mock_method = getattr(foo, method_name)
|
|
|
|
# check that the methods are callable with correct args.
|
|
mock_method(mock.sentinel.a, mock.sentinel.b, mock.sentinel.c)
|
|
mock_method(mock.sentinel.a, mock.sentinel.b, mock.sentinel.c,
|
|
d=mock.sentinel.d)
|
|
mock_method.assert_has_calls([
|
|
mock.call(mock.sentinel.a, mock.sentinel.b, mock.sentinel.c),
|
|
mock.call(mock.sentinel.a, mock.sentinel.b, mock.sentinel.c,
|
|
d=mock.sentinel.d)])
|
|
|
|
# assert that TypeError is raised if the method signature is not
|
|
# respected.
|
|
self.assertRaises(TypeError, mock_method)
|
|
self.assertRaises(TypeError, mock_method, mock.sentinel.a)
|
|
self.assertRaises(TypeError, mock_method, a=mock.sentinel.a)
|
|
self.assertRaises(TypeError, mock_method, mock.sentinel.a,
|
|
mock.sentinel.b, mock.sentinel.c,
|
|
e=mock.sentinel.e)
|
|
|
|
# assert that AttributeError is raised if the method does not exist.
|
|
self.assertRaises(AttributeError, getattr, foo, 'lish')
|
|
|
|
def _check_mock_autospec_all_members(self, mock_cls):
|
|
for spec in [Foo, Foo()]:
|
|
foo = mock_cls(autospec=spec)
|
|
self._check_autospeced_foo(foo)
|
|
self._check_autospeced_foo(foo())
|
|
|
|
def test_mock_autospec_all_members(self):
|
|
self._check_mock_autospec_all_members(mock.Mock)
|
|
|
|
def test_magic_mock_autospec_all_members(self):
|
|
self._check_mock_autospec_all_members(mock.MagicMock)
|
|
|
|
@mock.patch.object(Foo, 'static_bar')
|
|
@mock.patch.object(Foo, 'classic_bar')
|
|
@mock.patch.object(Foo, 'bar')
|
|
def test_patch_autospec_class(self, mock_meth, mock_cmeth, mock_smeth):
|
|
foo = Foo()
|
|
self._check_autospeced_foo(foo)
|
|
|
|
def test_patch_autospec_multiple(self):
|
|
with mock.patch.multiple(Foo, bar=mock.DEFAULT,
|
|
classic_bar=mock.DEFAULT,
|
|
static_bar=mock.DEFAULT):
|
|
foo = Foo()
|
|
self._check_autospeced_foo(foo)
|
|
|
|
@mock.patch.object(Foo, 'static_bar', autospec=False)
|
|
@mock.patch.object(Foo, 'classic_bar', autospec=False)
|
|
@mock.patch.object(Foo, 'bar', autospec=False)
|
|
def test_patch_autospec_class_false(self, mock_meth, mock_cmeth,
|
|
mock_smeth):
|
|
foo = Foo()
|
|
# we're checking that method signature is not enforced.
|
|
foo.bar()
|
|
mock_meth.assert_called_once_with()
|
|
foo.classic_bar()
|
|
mock_cmeth.assert_called_once_with()
|
|
foo.static_bar()
|
|
mock_smeth.assert_called_once_with()
|
|
|
|
@mock.patch.object(Foo, 'lish', create=True)
|
|
def test_patch_create(self, mock_lish):
|
|
foo = Foo()
|
|
|
|
foo.lish()
|
|
mock_lish.assert_called_once_with()
|