summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--mocker.py30
-rwxr-xr-xtest.py27
3 files changed, 51 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 1a45ebc..6ba674c 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@
environments which inspect the result's type, such as in iPython
(reported by Alex Dante).
+- Now Mocker.mock()/proxy()/replace() accept a 'count' keyword
+ parameter, which if set to False, the default behavior of allowing
+ expressions just once is disabled.
+
0.9.1 (2007-11-18)
==================
diff --git a/mocker.py b/mocker.py
index c18f204..41c0c36 100644
--- a/mocker.py
+++ b/mocker.py
@@ -463,7 +463,8 @@ class MockerBase(object):
message.append("")
raise AssertionError(os.linesep.join(message))
- def mock(self, spec_and_type=None, spec=None, type=None, name=None):
+ def mock(self, spec_and_type=None, spec=None, type=None,
+ name=None, count=True):
"""Return a new mock object.
@param spec_and_type: Handy positional argument which sets both
@@ -476,12 +477,17 @@ class MockerBase(object):
@param name: Name for the mock object, used in the representation of
expressions. The name is rarely needed, as it's usually
guessed correctly from the variable name used.
+ @param count: If set to false, expressions may be executed any number
+ of times, unless an expectation is explicitly set using
+ the L{count()} method. By default, expressions are
+ expected once.
"""
if spec_and_type is not None:
spec = type = spec_and_type
- return Mock(self, spec=spec, type=type, name=name)
+ return Mock(self, spec=spec, type=type, name=name, count=count)
- def proxy(self, object, spec=True, type=True, name=None, passthrough=True):
+ def proxy(self, object, spec=True, type=True, name=None, count=True,
+ passthrough=True):
"""Return a new mock object which proxies to the given object.
Proxies are useful when only part of the behavior of an object
@@ -508,6 +514,10 @@ class MockerBase(object):
@param name: Name for the mock object, used in the representation of
expressions. The name is rarely needed, as it's usually
guessed correctly from the variable name used.
+ @param count: If set to false, expressions may be executed any number
+ of times, unless an expectation is explicitly set using
+ the L{count()} method. By default, expressions are
+ expected once.
@param passthrough: If set to False, passthrough of actions on the
proxy to the real object will only happen when
explicitly requested via the L{passthrough()}
@@ -536,9 +546,9 @@ class MockerBase(object):
if type is True:
type = __builtin__.type(object)
return Mock(self, spec=spec, type=type, object=object,
- name=name, passthrough=passthrough)
+ name=name, count=count, passthrough=passthrough)
- def replace(self, object, spec=True, type=True, name=None,
+ def replace(self, object, spec=True, type=True, name=None, count=True,
passthrough=True):
"""Create a proxy, and replace the original object with the mock.
@@ -570,7 +580,7 @@ class MockerBase(object):
explicitly requested via the L{passthrough()}
method.
"""
- mock = self.proxy(object, spec, type, name, passthrough)
+ mock = self.proxy(object, spec, type, name, count, passthrough)
event = self._get_replay_restore_event()
event.add_task(ProxyReplacer(mock))
return mock
@@ -944,7 +954,7 @@ recorder = Mocker.add_recorder
class Mock(object):
def __init__(self, mocker, path=None, name=None, spec=None, type=None,
- object=None, passthrough=False, patcher=None):
+ object=None, passthrough=False, patcher=None, count=True):
self.__mocker__ = mocker
self.__mocker_path__ = path or Path(self, object)
self.__mocker_name__ = name
@@ -954,6 +964,7 @@ class Mock(object):
self.__mocker_patcher__ = patcher
self.__mocker_replace__ = False
self.__mocker_type__ = type
+ self.__mocker_count__ = count
def __mocker_act__(self, kind, args=(), kwargs={}, object=None):
if self.__mocker_name__ is None:
@@ -1600,8 +1611,9 @@ class ImplicitRunCounter(RunCounter):
@recorder
def run_counter_recorder(mocker, event):
- """In principle, any event may be repeated once."""
- event.add_task(ImplicitRunCounter(1))
+ """Any event may be repeated once, unless disabled by default."""
+ if event.path.root_mock.__mocker_count__:
+ event.add_task(ImplicitRunCounter(1))
@recorder
def run_counter_removal_recorder(mocker, event):
diff --git a/test.py b/test.py
index ce984b1..f4f8291 100755
--- a/test.py
+++ b/test.py
@@ -977,6 +977,13 @@ class MockerTest(unittest.TestCase):
MyMocker.remove_recorder(obj1)
self.assertEquals(MyMocker.get_recorders(), [obj2])
+ def test_mock(self):
+ mock = self.mocker.mock()
+ self.assertEquals(mock.__mocker_name__, None)
+ self.assertEquals(mock.__mocker_spec__, None)
+ self.assertEquals(mock.__mocker_type__, None)
+ self.assertEquals(mock.__mocker_count__, True)
+
def test_mock_with_name(self):
mock = self.mocker.mock(name="name")
self.assertEquals(mock.__mocker_name__, "name")
@@ -997,12 +1004,23 @@ class MockerTest(unittest.TestCase):
self.assertEquals(mock.__mocker_spec__, C)
self.assertEquals(mock.__mocker_type__, C)
+ def test_mock_with_count(self):
+ class C(object): pass
+ mock = self.mocker.mock(count=False)
+ self.assertEquals(mock.__mocker_count__, False)
+
def test_proxy(self):
original = object()
mock = self.mocker.proxy(original)
self.assertEquals(type(mock), Mock)
self.assertEquals(mock.__mocker_object__, original)
self.assertEquals(mock.__mocker_path__.root_object, original)
+ self.assertEquals(mock.__mocker_count__, True)
+
+ def test_proxy_with_count(self):
+ original = object()
+ mock = self.mocker.proxy(original, count=False)
+ self.assertEquals(mock.__mocker_count__, False)
def test_proxy_with_spec(self):
original = object()
@@ -1063,13 +1081,14 @@ class MockerTest(unittest.TestCase):
def test_replace(self):
from os import path
obj = object()
- proxy = self.mocker.replace(obj, spec=object, name="obj",
+ proxy = self.mocker.replace(obj, spec=object, name="obj", count=False,
passthrough=False)
self.assertEquals(type(proxy), Mock)
self.assertEquals(type(proxy.__mocker_object__), object)
self.assertEquals(proxy.__mocker_object__, obj)
self.assertEquals(proxy.__mocker_spec__, object)
self.assertEquals(proxy.__mocker_name__, "obj")
+ self.assertEquals(proxy.__mocker_count__, False)
(event,) = self.mocker.get_events()
self.assertEquals(type(event), ReplayRestoreEvent)
(task,) = event.get_tasks()
@@ -2065,6 +2084,7 @@ class MockTest(unittest.TestCase):
self.assertEquals(self.mock.__mocker_passthrough__, False)
self.assertEquals(self.mock.__mocker_patcher__, None)
self.assertEquals(self.mock.__mocker_replace__, False)
+ self.assertEquals(self.mock.__mocker_count__, True)
def test_path(self):
path = object()
@@ -2675,6 +2695,11 @@ class RunCounterTest(unittest.TestCase):
self.assertTrue(task.min == 1)
self.assertTrue(task.max == 1)
+ def test_recorder_wont_record_when_count_is_false(self):
+ self.mock.__mocker_count__ = False
+ run_counter_recorder(self.mocker, self.event)
+ self.assertEquals(self.event.get_tasks(), [])
+
def test_removal_recorder(self):
"""
Events created by getattr actions which lead to other events