From 08be09df430c5175fc7022dba18c7684d3f94389 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 9 Feb 2015 15:21:11 +0100 Subject: [PATCH] Add a new mockpatch fixture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixture provides an easy usage for mock (unittest.mock in Python 3). --- fixtures/__init__.py | 6 ++ fixtures/_fixtures/__init__.py | 8 +++ fixtures/_fixtures/mockpatch.py | 71 +++++++++++++++++++++ fixtures/tests/_fixtures/__init__.py | 1 + fixtures/tests/_fixtures/test_mockpatch.py | 74 ++++++++++++++++++++++ requirements.txt | 1 + 6 files changed, 161 insertions(+) create mode 100644 fixtures/_fixtures/mockpatch.py create mode 100644 fixtures/tests/_fixtures/test_mockpatch.py diff --git a/fixtures/__init__.py b/fixtures/__init__.py index d8647d2..577d2e1 100644 --- a/fixtures/__init__.py +++ b/fixtures/__init__.py @@ -54,6 +54,9 @@ __all__ = [ 'LogHandler', 'LoggerFixture', 'MethodFixture', + 'MockPatch', + 'MockPatchMultiple', + 'MockPatchObject', 'MonkeyPatch', 'NestedTempfile', 'PackagePathEntry', @@ -86,6 +89,9 @@ from fixtures._fixtures import ( FakePopen, LoggerFixture, LogHandler, + MockPatch, + MockPatchMultiple, + MockPatchObject, MonkeyPatch, NestedTempfile, PackagePathEntry, diff --git a/fixtures/_fixtures/__init__.py b/fixtures/_fixtures/__init__.py index 48a923a..b60a6fb 100644 --- a/fixtures/_fixtures/__init__.py +++ b/fixtures/_fixtures/__init__.py @@ -25,6 +25,9 @@ __all__ = [ 'FakePopen', 'LoggerFixture', 'LogHandler', + 'MockPatch', + 'MockPatchMultiple', + 'MockPatchObject', 'MonkeyPatch', 'NestedTempfile', 'PackagePathEntry', @@ -49,6 +52,11 @@ from fixtures._fixtures.logger import ( LoggerFixture, LogHandler, ) +from fixtures._fixtures.mockpatch import ( + MockPatch, + MockPatchMultiple, + MockPatchObject, + ) from fixtures._fixtures.monkeypatch import MonkeyPatch from fixtures._fixtures.popen import ( FakePopen, diff --git a/fixtures/_fixtures/mockpatch.py b/fixtures/_fixtures/mockpatch.py new file mode 100644 index 0000000..12d86af --- /dev/null +++ b/fixtures/_fixtures/mockpatch.py @@ -0,0 +1,71 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# 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 fixtures + +try: + from unittest import mock +except ImportError: + import mock + + +class _Base(fixtures.Fixture): + def setUp(self): + super(_Base, self).setUp() + _p = self._get_p() + self.addCleanup(_p.stop) + self.mock = _p.start() + + +class MockPatchObject(_Base): + """Deal with code around mock.""" + + def __init__(self, obj, attr, new=mock.DEFAULT, **kwargs): + super(MockPatchObject, self).__init__() + self._get_p = lambda: mock.patch.object(obj, attr, new, **kwargs) + + +class MockPatch(_Base): + """Deal with code around mock.patch.""" + + def __init__(self, obj, new=mock.DEFAULT, **kwargs): + super(MockPatch, self).__init__() + self._get_p = lambda: mock.patch(obj, new, **kwargs) + + +class MockPatchMultiple(_Base): + """Deal with code around mock.patch.multiple.""" + + # Default value to trigger a MagicMock to be created for a named + # attribute. + DEFAULT = mock.DEFAULT + + def __init__(self, obj, **kwargs): + """Initialize the mocks + + Pass name=value to replace obj.name with value. + + Pass name=Multiple.DEFAULT to replace obj.name with a + MagicMock instance. + + :param obj: Object or name containing values being mocked. + :type obj: str or object + :param kwargs: names and values of attributes of obj to be mocked. + + """ + super(MockPatchMultiple, self).__init__() + self._get_p = lambda: mock.patch.multiple(obj, **kwargs) diff --git a/fixtures/tests/_fixtures/__init__.py b/fixtures/tests/_fixtures/__init__.py index e4d9403..1b4c359 100644 --- a/fixtures/tests/_fixtures/__init__.py +++ b/fixtures/tests/_fixtures/__init__.py @@ -17,6 +17,7 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ 'environ', 'logger', + 'mockpatch', 'monkeypatch', 'packagepath', 'popen', diff --git a/fixtures/tests/_fixtures/test_mockpatch.py b/fixtures/tests/_fixtures/test_mockpatch.py new file mode 100644 index 0000000..75d70fe --- /dev/null +++ b/fixtures/tests/_fixtures/test_mockpatch.py @@ -0,0 +1,74 @@ +# Copyright 2014 IBM Corp. +# +# 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. + +try: + from unittest import mock +except ImportError: + import mock + +import testtools + +from fixtures import ( + MockPatch, + MockPatchMultiple, + MockPatchObject, +) + + +class Foo(object): + def bar(self): + return self + + +def mocking_bar(self): + return 'mocked!' + + +class TestMockPatch(testtools.TestCase): + def test_mock_patch_with_replacement(self): + self.useFixture(MockPatch('%s.Foo.bar' % (__name__), mocking_bar)) + instance = Foo() + self.assertEqual(instance.bar(), 'mocked!') + + def test_mock_patch_without_replacement(self): + self.useFixture(MockPatch('%s.Foo.bar' % (__name__))) + instance = Foo() + self.assertIsInstance(instance.bar(), mock.MagicMock) + + +class TestMockMultiple(testtools.TestCase): + def test_mock_multiple_with_replacement(self): + self.useFixture(MockPatchMultiple('%s.Foo' % (__name__), + bar=mocking_bar)) + instance = Foo() + self.assertEqual(instance.bar(), 'mocked!') + + def test_mock_patch_without_replacement(self): + self.useFixture(MockPatchMultiple( + '%s.Foo' % (__name__), + bar=MockPatchMultiple.DEFAULT)) + instance = Foo() + self.assertIsInstance(instance.bar(), mock.MagicMock) + + +class TestMockPatchObject(testtools.TestCase): + def test_mock_patch_object_with_replacement(self): + self.useFixture(MockPatchObject(Foo, 'bar', mocking_bar)) + instance = Foo() + self.assertEqual(instance.bar(), 'mocked!') + + def test_mock_patch_object_without_replacement(self): + self.useFixture(MockPatchObject(Foo, 'bar')) + instance = Foo() + self.assertIsInstance(instance.bar(), mock.MagicMock) diff --git a/requirements.txt b/requirements.txt index f9efc61..cc78151 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pbr>=0.11 testtools>=0.9.22 +mock