4
Graceful platform for test doubles in Python: mocks, stubs, fakes, and dummies.
6
Copyright (c) 2007-2010, Gustavo Niemeyer <gustavo@niemeyer.net>
10
Redistribution and use in source and binary forms, with or without
11
modification, are permitted provided that the following conditions are met:
13
* Redistributions of source code must retain the above copyright notice,
14
this list of conditions and the following disclaimer.
15
* Redistributions in binary form must reproduce the above copyright notice,
16
this list of conditions and the following disclaimer in the documentation
17
and/or other materials provided with the distribution.
18
* Neither the name of the copyright holder nor the names of its
19
contributors may be used to endorse or promote products derived from
20
this software without specific prior written permission.
22
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
if sys.version_info < (2, 4):
46
from sets import Set as set # pragma: nocover
49
__all__ = ["Mocker", "Expect", "expect", "IS", "CONTAINS", "IN", "MATCH",
50
"ANY", "ARGS", "KWARGS", "MockerTestCase"]
53
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
58
ERROR_PREFIX = "[Mocker] "
61
# --------------------------------------------------------------------
64
class MatchError(AssertionError):
65
"""Raised when an unknown expression is seen in playback mode."""
68
# --------------------------------------------------------------------
69
# Helper for chained-style calling.
72
"""This is a simple helper that allows a different call-style.
74
With this class one can comfortably do chaining of calls to the
75
mocker object responsible by the object being handled. For instance::
77
expect(obj.attr).result(3).count(1, 2)
89
def __init__(self, mock, attr=None):
93
def __getattr__(self, attr):
94
return self.__class__(self._mock, attr)
96
def __call__(self, *args, **kwargs):
97
mocker = self.__mocker__
99
mocker = self._mock.__mocker__
100
getattr(mocker, self._attr)(*args, **kwargs)
105
"""Create an expect() "function" using the given Mocker instance.
107
This helper allows defining an expect() "function" which works even
108
in trickier cases such as:
110
expect = Expect(mymocker)
111
expect(iter(mock)).generate([1, 2, 3])
114
return type("Expect", (expect,), {"__mocker__": mocker})
117
# --------------------------------------------------------------------
118
# Extensions to Python's unittest.
120
class MockerTestCase(unittest.TestCase):
121
"""unittest.TestCase subclass with Mocker support.
123
@ivar mocker: The mocker instance.
125
This is a convenience only. Mocker may easily be used with the
126
standard C{unittest.TestCase} class if wanted.
128
Test methods have a Mocker instance available on C{self.mocker}.
129
At the end of each test method, expectations of the mocker will
130
be verified, and any requested changes made to the environment
133
In addition to the integration with Mocker, this class provides
134
a few additional helper methods.
137
def __init__(self, methodName="runTest"):
138
# So here is the trick: we take the real test method, wrap it on
139
# a function that do the job we have to do, and insert it in the
140
# *instance* dictionary, so that getattr() will return our
141
# replacement rather than the class method.
142
test_method = getattr(self, methodName, None)
143
if test_method is not None:
144
def test_method_wrapper():
146
result = test_method()
150
if (self.mocker.is_recording() and
151
self.mocker.get_events()):
152
raise RuntimeError("Mocker must be put in replay "
153
"mode with self.mocker.replay()")
154
if (hasattr(result, "addCallback") and
155
hasattr(result, "addErrback")):
159
result.addCallback(verify)
162
self.mocker.restore()
164
# Copy all attributes from the original method..
165
for attr in dir(test_method):
166
# .. unless they're present in our wrapper already.
167
if not hasattr(test_method_wrapper, attr) or attr == "__doc__":
168
setattr(test_method_wrapper, attr,
169
getattr(test_method, attr))
170
setattr(self, methodName, test_method_wrapper)
172
# We could overload run() normally, but other well-known testing
173
# frameworks do it as well, and some of them won't call the super,
174
# which might mean that cleanup wouldn't happen. With that in mind,
175
# we make integration easier by using the following trick.
176
run_method = self.run
177
def run_wrapper(*args, **kwargs):
179
return run_method(*args, **kwargs)
182
self.run = run_wrapper
184
self.mocker = Mocker()
185
self.expect = Expect(self.mocker)
187
self.__cleanup_funcs = []
188
self.__cleanup_paths = []
190
super(MockerTestCase, self).__init__(methodName)
192
def __call__(self, *args, **kwargs):
193
# This is necessary for Python 2.3 only, because it didn't use run(),
194
# which is supported above.
196
super(MockerTestCase, self).__call__(*args, **kwargs)
198
if sys.version_info < (2, 4):
202
for path in self.__cleanup_paths:
203
if os.path.isfile(path):
205
elif os.path.isdir(path):
208
for func, args, kwargs in self.__cleanup_funcs:
209
func(*args, **kwargs)
211
def addCleanup(self, func, *args, **kwargs):
212
self.__cleanup_funcs.append((func, args, kwargs))
214
def makeFile(self, content=None, suffix="", prefix="tmp", basename=None,
215
dirname=None, path=None):
216
"""Create a temporary file and return the path to it.
218
@param content: Initial content for the file.
219
@param suffix: Suffix to be given to the file's basename.
220
@param prefix: Prefix to be given to the file's basename.
221
@param basename: Full basename for the file.
222
@param dirname: Put file inside this directory.
224
The file is removed after the test runs.
227
self.__cleanup_paths.append(path)
228
elif basename is not None:
230
dirname = tempfile.mkdtemp()
231
self.__cleanup_paths.append(dirname)
232
path = os.path.join(dirname, basename)
234
fd, path = tempfile.mkstemp(suffix, prefix, dirname)
235
self.__cleanup_paths.append(path)
239
if content is not None:
240
file = open(path, "w")
245
def makeDir(self, suffix="", prefix="tmp", dirname=None, path=None):
246
"""Create a temporary directory and return the path to it.
248
@param suffix: Suffix to be given to the file's basename.
249
@param prefix: Prefix to be given to the file's basename.
250
@param dirname: Put directory inside this parent directory.
252
The directory is removed after the test runs.
257
path = tempfile.mkdtemp(suffix, prefix, dirname)
258
self.__cleanup_paths.append(path)
261
def failUnlessIs(self, first, second, msg=None):
262
"""Assert that C{first} is the same object as C{second}."""
263
if first is not second:
264
raise self.failureException(msg or "%r is not %r" % (first, second))
266
def failIfIs(self, first, second, msg=None):
267
"""Assert that C{first} is not the same object as C{second}."""
269
raise self.failureException(msg or "%r is %r" % (first, second))
271
def failUnlessIn(self, first, second, msg=None):
272
"""Assert that C{first} is contained in C{second}."""
273
if first not in second:
274
raise self.failureException(msg or "%r not in %r" % (first, second))
276
def failUnlessStartsWith(self, first, second, msg=None):
277
"""Assert that C{first} starts with C{second}."""
278
if first[:len(second)] != second:
279
raise self.failureException(msg or "%r doesn't start with %r" %
282
def failIfStartsWith(self, first, second, msg=None):
283
"""Assert that C{first} doesn't start with C{second}."""
284
if first[:len(second)] == second:
285
raise self.failureException(msg or "%r starts with %r" %
288
def failUnlessEndsWith(self, first, second, msg=None):
289
"""Assert that C{first} starts with C{second}."""
290
if first[len(first)-len(second):] != second:
291
raise self.failureException(msg or "%r doesn't end with %r" %
294
def failIfEndsWith(self, first, second, msg=None):
295
"""Assert that C{first} doesn't start with C{second}."""
296
if first[len(first)-len(second):] == second:
297
raise self.failureException(msg or "%r ends with %r" %
300
def failIfIn(self, first, second, msg=None):
301
"""Assert that C{first} is not contained in C{second}."""
303
raise self.failureException(msg or "%r in %r" % (first, second))
305
def failUnlessApproximates(self, first, second, tolerance, msg=None):
306
"""Assert that C{first} is near C{second} by at most C{tolerance}."""
307
if abs(first - second) > tolerance:
308
raise self.failureException(msg or "abs(%r - %r) > %r" %
309
(first, second, tolerance))
311
def failIfApproximates(self, first, second, tolerance, msg=None):
312
"""Assert that C{first} is far from C{second} by at least C{tolerance}.
314
if abs(first - second) <= tolerance:
315
raise self.failureException(msg or "abs(%r - %r) <= %r" %
316
(first, second, tolerance))
318
def failUnlessMethodsMatch(self, first, second):
319
"""Assert that public methods in C{first} are present in C{second}.
321
This method asserts that all public methods found in C{first} are also
322
present in C{second} and accept the same arguments. C{first} may
323
have its own private methods, though, and may not have all methods
324
found in C{second}. Note that if a private method in C{first} matches
325
the name of one in C{second}, their specification is still compared.
327
This is useful to verify if a fake or stub class have the same API as
328
the real class being simulated.
330
first_methods = dict(inspect.getmembers(first, inspect.ismethod))
331
second_methods = dict(inspect.getmembers(second, inspect.ismethod))
332
for name, first_method in first_methods.iteritems():
333
first_argspec = inspect.getargspec(first_method)
334
first_formatted = inspect.formatargspec(*first_argspec)
336
second_method = second_methods.get(name)
337
if second_method is None:
339
continue # First may have its own private methods.
340
raise self.failureException("%s.%s%s not present in %s" %
341
(first.__name__, name, first_formatted, second.__name__))
343
second_argspec = inspect.getargspec(second_method)
344
if first_argspec != second_argspec:
345
second_formatted = inspect.formatargspec(*second_argspec)
346
raise self.failureException("%s.%s%s != %s.%s%s" %
347
(first.__name__, name, first_formatted,
348
second.__name__, name, second_formatted))
350
def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
352
Fail unless an exception of class excClass is thrown by callableObj
353
when invoked with arguments args and keyword arguments kwargs. If a
354
different type of exception is thrown, it will not be caught, and the
355
test case will be deemed to have suffered an error, exactly as for an
356
unexpected exception. It returns the exception instance if it matches
357
the given exception class.
360
result = callableObj(*args, **kwargs)
365
if hasattr(excClass, "__name__"):
366
excName = excClass.__name__
367
raise self.failureException(
368
"%s not raised (%r returned)" % (excName, result))
371
assertIs = failUnlessIs
372
assertIsNot = failIfIs
373
assertIn = failUnlessIn
374
assertNotIn = failIfIn
375
assertStartsWith = failUnlessStartsWith
376
assertNotStartsWith = failIfStartsWith
377
assertEndsWith = failUnlessEndsWith
378
assertNotEndsWith = failIfEndsWith
379
assertApproximates = failUnlessApproximates
380
assertNotApproximates = failIfApproximates
381
assertMethodsMatch = failUnlessMethodsMatch
382
assertRaises = failUnlessRaises
384
# The following are missing in Python < 2.4.
385
assertTrue = unittest.TestCase.failUnless
386
assertFalse = unittest.TestCase.failIf
388
# The following is provided for compatibility with Twisted's trial.
389
assertIdentical = assertIs
390
assertNotIdentical = assertIsNot
391
failUnlessIdentical = failUnlessIs
392
failIfIdentical = failIfIs
395
# --------------------------------------------------------------------
398
class classinstancemethod(object):
400
def __init__(self, method):
403
def __get__(self, obj, cls=None):
404
def bound_method(*args, **kwargs):
405
return self.method(cls, obj, *args, **kwargs)
409
class MockerBase(object):
410
"""Controller of mock objects.
412
A mocker instance is used to command recording and replay of
413
expectations on any number of mock objects.
415
Expectations should be expressed for the mock object while in
416
record mode (the initial one) by using the mock object itself,
417
and using the mocker (and/or C{expect()} as a helper) to define
418
additional behavior for each event. For instance::
424
assert mock.hello() == "Hi!"
428
In this short excerpt a mock object is being created, then an
429
expectation of a call to the C{hello()} method was recorded, and
430
when called the method should return the value C{10}. Then, the
431
mocker is put in replay mode, and the expectation is satisfied by
432
calling the C{hello()} method, which indeed returns 10. Finally,
433
a call to the L{restore()} method is performed to undo any needed
434
changes made in the environment, and the L{verify()} method is
435
called to ensure that all defined expectations were met.
437
The same logic can be expressed more elegantly using the
438
C{with mocker:} statement, as follows::
444
assert mock.hello() == "Hi!"
446
Also, the MockerTestCase class, which integrates the mocker on
447
a unittest.TestCase subclass, may be used to reduce the overhead
448
of controlling the mocker. A test could be written as follows::
450
class SampleTest(MockerTestCase):
452
def test_hello(self):
453
mock = self.mocker.mock()
455
self.mocker.result("Hi!")
457
self.assertEquals(mock.hello(), "Hi!")
462
# For convenience only.
465
class __metaclass__(type):
466
def __init__(self, name, bases, dict):
467
# Make independent lists on each subclass, inheriting from parent.
468
self._recorders = list(getattr(self, "_recorders", ()))
471
self._recorders = self._recorders[:]
473
self._recording = True
474
self._ordering = False
475
self._last_orderer = None
477
def is_recording(self):
478
"""Return True if in recording mode, False if in replay mode.
480
Recording is the initial state.
482
return self._recording
485
"""Change to replay mode, where recorded events are reproduced.
487
If already in replay mode, the mocker will be restored, with all
488
expectations reset, and then put again in replay mode.
490
An alternative and more comfortable way to replay changes is
491
using the 'with' statement, as follows::
498
The 'with' statement will automatically put mocker in replay
499
mode, and will also verify if all events were correctly reproduced
500
at the end (using L{verify()}), and also restore any changes done
501
in the environment (with L{restore()}).
503
Also check the MockerTestCase class, which integrates the
504
unittest.TestCase class with mocker.
506
if not self._recording:
507
for event in self._events:
510
self._recording = False
511
for event in self._events:
515
"""Restore changes in the environment, and return to recording mode.
517
This should always be called after the test is complete (succeeding
518
or not). There are ways to call this method automatically on
519
completion (e.g. using a C{with mocker:} statement, or using the
520
L{MockerTestCase} class.
522
if not self._recording:
523
self._recording = True
524
for event in self._events:
528
"""Reset the mocker state.
530
This will restore environment changes, if currently in replay
531
mode, and then remove all events previously recorded.
533
if not self._recording:
538
def get_events(self):
539
"""Return all recorded events."""
540
return self._events[:]
542
def add_event(self, event):
545
This method is used internally by the implementation, and
546
shouldn't be needed on normal mocker usage.
548
self._events.append(event)
550
orderer = event.add_task(Orderer(event.path))
551
if self._last_orderer:
552
orderer.add_dependency(self._last_orderer)
553
self._last_orderer = orderer
557
"""Check if all expectations were met, and raise AssertionError if not.
559
The exception message will include a nice description of which
560
expectations were not met, and why.
563
for event in self._events:
566
except AssertionError, e:
569
raise RuntimeError("Empty error message from %r"
573
message = [ERROR_PREFIX + "Unmet expectations:", ""]
575
lines = error.splitlines()
576
message.append("=> " + lines.pop(0))
577
message.extend([" " + line for line in lines])
579
raise AssertionError(os.linesep.join(message))
581
def mock(self, spec_and_type=None, spec=None, type=None,
582
name=None, count=True):
583
"""Return a new mock object.
585
@param spec_and_type: Handy positional argument which sets both
587
@param spec: Method calls will be checked for correctness against
589
@param type: If set, the Mock's __class__ attribute will return
590
the given type. This will make C{isinstance()} calls
592
@param name: Name for the mock object, used in the representation of
593
expressions. The name is rarely needed, as it's usually
594
guessed correctly from the variable name used.
595
@param count: If set to false, expressions may be executed any number
596
of times, unless an expectation is explicitly set using
597
the L{count()} method. By default, expressions are
600
if spec_and_type is not None:
601
spec = type = spec_and_type
602
return Mock(self, spec=spec, type=type, name=name, count=count)
604
def proxy(self, object, spec=True, type=True, name=None, count=True,
606
"""Return a new mock object which proxies to the given object.
608
Proxies are useful when only part of the behavior of an object
609
is to be mocked. Unknown expressions may be passed through to
610
the real implementation implicitly (if the C{passthrough} argument
611
is True), or explicitly (using the L{passthrough()} method
614
@param object: Real object to be proxied, and replaced by the mock
615
on replay mode. It may also be an "import path",
616
such as C{"time.time"}, in which case the object
617
will be the C{time} function from the C{time} module.
618
@param spec: Method calls will be checked for correctness against
619
the given object, which may be a class or an instance
620
where attributes will be looked up. Defaults to the
621
the C{object} parameter. May be set to None explicitly,
622
in which case spec checking is disabled. Checks may
623
also be disabled explicitly on a per-event basis with
624
the L{nospec()} method.
625
@param type: If set, the Mock's __class__ attribute will return
626
the given type. This will make C{isinstance()} calls
627
on the object work. Defaults to the type of the
628
C{object} parameter. May be set to None explicitly.
629
@param name: Name for the mock object, used in the representation of
630
expressions. The name is rarely needed, as it's usually
631
guessed correctly from the variable name used.
632
@param count: If set to false, expressions may be executed any number
633
of times, unless an expectation is explicitly set using
634
the L{count()} method. By default, expressions are
636
@param passthrough: If set to False, passthrough of actions on the
637
proxy to the real object will only happen when
638
explicitly requested via the L{passthrough()}
641
if isinstance(object, basestring):
644
import_stack = object.split(".")
647
module_path = ".".join(import_stack)
649
__import__(module_path)
651
attr_stack.insert(0, import_stack.pop())
656
object = sys.modules[module_path]
657
for attr in attr_stack:
658
object = getattr(object, attr)
660
if isinstance(object, types.UnboundMethodType):
661
object = object.im_func
665
type = __builtin__.type(object)
666
return Mock(self, spec=spec, type=type, object=object,
667
name=name, count=count, passthrough=passthrough)
669
def replace(self, object, spec=True, type=True, name=None, count=True,
671
"""Create a proxy, and replace the original object with the mock.
673
On replay, the original object will be replaced by the returned
674
proxy in all dictionaries found in the running interpreter via
675
the garbage collecting system. This should cover module
676
namespaces, class namespaces, instance namespaces, and so on.
678
@param object: Real object to be proxied, and replaced by the mock
679
on replay mode. It may also be an "import path",
680
such as C{"time.time"}, in which case the object
681
will be the C{time} function from the C{time} module.
682
@param spec: Method calls will be checked for correctness against
683
the given object, which may be a class or an instance
684
where attributes will be looked up. Defaults to the
685
the C{object} parameter. May be set to None explicitly,
686
in which case spec checking is disabled. Checks may
687
also be disabled explicitly on a per-event basis with
688
the L{nospec()} method.
689
@param type: If set, the Mock's __class__ attribute will return
690
the given type. This will make C{isinstance()} calls
691
on the object work. Defaults to the type of the
692
C{object} parameter. May be set to None explicitly.
693
@param name: Name for the mock object, used in the representation of
694
expressions. The name is rarely needed, as it's usually
695
guessed correctly from the variable name used.
696
@param passthrough: If set to False, passthrough of actions on the
697
proxy to the real object will only happen when
698
explicitly requested via the L{passthrough()}
701
mock = self.proxy(object, spec, type, name, count, passthrough)
702
event = self._get_replay_restore_event()
703
event.add_task(ProxyReplacer(mock))
706
def patch(self, object, spec=True):
707
"""Patch an existing object to reproduce recorded events.
709
@param object: Class or instance to be patched.
710
@param spec: Method calls will be checked for correctness against
711
the given object, which may be a class or an instance
712
where attributes will be looked up. Defaults to the
713
the C{object} parameter. May be set to None explicitly,
714
in which case spec checking is disabled. Checks may
715
also be disabled explicitly on a per-event basis with
716
the L{nospec()} method.
718
The result of this method is still a mock object, which can be
719
used like any other mock object to record events. The difference
720
is that when the mocker is put on replay mode, the *real* object
721
will be modified to behave according to recorded expectations.
723
Patching works in individual instances, and also in classes.
724
When an instance is patched, recorded events will only be
725
considered on this specific instance, and other instances should
726
behave normally. When a class is patched, the reproduction of
727
events will be considered on any instance of this class once
728
created (collectively).
730
Observe that, unlike with proxies which catch only events done
731
through the mock object, *all* accesses to recorded expectations
732
will be considered; even these coming from the object itself
733
(e.g. C{self.hello()} is considered if this method was patched).
734
While this is a very powerful feature, and many times the reason
735
to use patches in the first place, it's important to keep this
738
Patching of the original object only takes place when the mocker
739
is put on replay mode, and the patched object will be restored
740
to its original state once the L{restore()} method is called
741
(explicitly, or implicitly with alternative conventions, such as
742
a C{with mocker:} block, or a MockerTestCase class).
747
event = self._get_replay_restore_event()
748
event.add_task(patcher)
749
mock = Mock(self, object=object, patcher=patcher,
750
passthrough=True, spec=spec)
751
patcher.patch_attr(object, '__mocker_mock__', mock)
755
"""This is called by mock objects whenever something happens to them.
757
This method is part of the implementation between the mocker
761
event = self.add_event(Event(path))
762
for recorder in self._recorders:
763
recorder(self, event)
764
return Mock(self, path)
766
# First run events that may run, then run unsatisfied events, then
767
# ones not previously run. We put the index in the ordering tuple
768
# instead of the actual event because we want a stable sort
769
# (ordering between 2 events is undefined).
770
events = self._events
771
order = [(events[i].satisfied()*2 + events[i].has_run(), i)
772
for i in range(len(events))]
775
for weight, i in order:
777
if event.matches(path):
778
if event.may_run(path):
779
return event.run(path)
780
elif postponed is None:
782
if postponed is not None:
783
return postponed.run(path)
784
raise MatchError(ERROR_PREFIX + "Unexpected expression: %s" % path)
786
def get_recorders(cls, self):
787
"""Return recorders associated with this mocker class or instance.
789
This method may be called on mocker instances and also on mocker
790
classes. See the L{add_recorder()} method for more information.
792
return (self or cls)._recorders[:]
793
get_recorders = classinstancemethod(get_recorders)
795
def add_recorder(cls, self, recorder):
796
"""Add a recorder to this mocker class or instance.
798
@param recorder: Callable accepting C{(mocker, event)} as parameters.
800
This is part of the implementation of mocker.
802
All registered recorders are called for translating events that
803
happen during recording into expectations to be met once the state
804
is switched to replay mode.
806
This method may be called on mocker instances and also on mocker
807
classes. When called on a class, the recorder will be used by
808
all instances, and also inherited on subclassing. When called on
809
instances, the recorder is added only to the given instance.
811
(self or cls)._recorders.append(recorder)
813
add_recorder = classinstancemethod(add_recorder)
815
def remove_recorder(cls, self, recorder):
816
"""Remove the given recorder from this mocker class or instance.
818
This method may be called on mocker classes and also on mocker
819
instances. See the L{add_recorder()} method for more information.
821
(self or cls)._recorders.remove(recorder)
822
remove_recorder = classinstancemethod(remove_recorder)
824
def result(self, value):
825
"""Make the last recorded event return the given value on replay.
827
@param value: Object to be returned when the event is replayed.
829
self.call(lambda *args, **kwargs: value)
831
def generate(self, sequence):
832
"""Last recorded event will return a generator with the given sequence.
834
@param sequence: Sequence of values to be generated.
836
def generate(*args, **kwargs):
837
for value in sequence:
841
def throw(self, exception):
842
"""Make the last recorded event raise the given exception on replay.
844
@param exception: Class or instance of exception to be raised.
846
def raise_exception(*args, **kwargs):
848
self.call(raise_exception)
850
def call(self, func, with_object=False):
851
"""Make the last recorded event cause the given function to be called.
853
@param func: Function to be called.
855
The result of the function will be used as the event result.
857
event = self._events[-1]
858
if with_object and event.path.root_object is None:
859
raise TypeError("Mock object isn't a proxy")
860
event.add_task(FunctionRunner(func, with_root_object=with_object))
862
def count(self, min, max=False):
863
"""Last recorded event must be replayed between min and max times.
865
@param min: Minimum number of times that the event must happen.
866
@param max: Maximum number of times that the event must happen. If
867
not given, it defaults to the same value of the C{min}
868
parameter. If set to None, there is no upper limit, and
869
the expectation is met as long as it happens at least
872
event = self._events[-1]
873
for task in event.get_tasks():
874
if isinstance(task, RunCounter):
875
event.remove_task(task)
876
event.add_task(RunCounter(min, max))
878
def is_ordering(self):
879
"""Return true if all events are being ordered.
881
See the L{order()} method.
883
return self._ordering
886
"""Disable the ordered mode.
888
See the L{order()} method for more information.
890
self._ordering = False
891
self._last_orderer = None
893
def order(self, *path_holders):
894
"""Create an expectation of order between two or more events.
896
@param path_holders: Objects returned as the result of recorded events.
898
By default, mocker won't force events to happen precisely in
899
the order they were recorded. Calling this method will change
900
this behavior so that events will only match if reproduced in
903
There are two ways in which this method may be used. Which one
904
is used in a given occasion depends only on convenience.
906
If no arguments are passed, the mocker will be put in a mode where
907
all the recorded events following the method call will only be met
908
if they happen in order. When that's used, the mocker may be put
909
back in unordered mode by calling the L{unorder()} method, or by
910
using a 'with' block, like so::
912
with mocker.ordered():
915
In this case, only expressions in <record events> will be ordered,
916
and the mocker will be back in unordered mode after the 'with' block.
918
The second way to use it is by specifying precisely which events
919
should be ordered. As an example::
925
mocker.order(expr1, expr2, expr3)
927
This method of ordering only works when the expression returns
930
Also check the L{after()} and L{before()} methods, which are
931
alternative ways to perform this.
934
self._ordering = True
935
return OrderedContext(self)
938
for path_holder in path_holders:
939
if type(path_holder) is Path:
942
path = path_holder.__mocker_path__
943
for event in self._events:
944
if event.path is path:
945
for task in event.get_tasks():
946
if isinstance(task, Orderer):
950
orderer = Orderer(path)
951
event.add_task(orderer)
953
orderer.add_dependency(last_orderer)
954
last_orderer = orderer
957
def after(self, *path_holders):
958
"""Last recorded event must happen after events referred to.
960
@param path_holders: Objects returned as the result of recorded events
961
which should happen before the last recorded event
963
As an example, the idiom::
965
expect(mock.x).after(mock.y, mock.z)
967
is an alternative way to say::
972
mocker.order(expr_y, expr_x)
973
mocker.order(expr_z, expr_x)
975
See L{order()} for more information.
977
last_path = self._events[-1].path
978
for path_holder in path_holders:
979
self.order(path_holder, last_path)
981
def before(self, *path_holders):
982
"""Last recorded event must happen before events referred to.
984
@param path_holders: Objects returned as the result of recorded events
985
which should happen after the last recorded event
987
As an example, the idiom::
989
expect(mock.x).before(mock.y, mock.z)
991
is an alternative way to say::
996
mocker.order(expr_x, expr_y)
997
mocker.order(expr_x, expr_z)
999
See L{order()} for more information.
1001
last_path = self._events[-1].path
1002
for path_holder in path_holders:
1003
self.order(last_path, path_holder)
1006
"""Don't check method specification of real object on last event.
1008
By default, when using a mock created as the result of a call to
1009
L{proxy()}, L{replace()}, and C{patch()}, or when passing the spec
1010
attribute to the L{mock()} method, method calls on the given object
1011
are checked for correctness against the specification of the real
1012
object (or the explicitly provided spec).
1014
This method will disable that check specifically for the last
1017
event = self._events[-1]
1018
for task in event.get_tasks():
1019
if isinstance(task, SpecChecker):
1020
event.remove_task(task)
1022
def passthrough(self, result_callback=None):
1023
"""Make the last recorded event run on the real object once seen.
1025
@param result_callback: If given, this function will be called with
1026
the result of the *real* method call as the only argument.
1028
This can only be used on proxies, as returned by the L{proxy()}
1029
and L{replace()} methods, or on mocks representing patched objects,
1030
as returned by the L{patch()} method.
1032
event = self._events[-1]
1033
if event.path.root_object is None:
1034
raise TypeError("Mock object isn't a proxy")
1035
event.add_task(PathExecuter(result_callback))
1037
def __enter__(self):
1038
"""Enter in a 'with' context. This will run replay()."""
1042
def __exit__(self, type, value, traceback):
1043
"""Exit from a 'with' context.
1045
This will run restore() at all times, but will only run verify()
1046
if the 'with' block itself hasn't raised an exception. Exceptions
1047
in that block are never swallowed.
1054
def _get_replay_restore_event(self):
1055
"""Return unique L{ReplayRestoreEvent}, creating if needed.
1057
Some tasks only want to replay/restore. When that's the case,
1058
they shouldn't act on other events during replay. Also, they
1059
can all be put in a single event when that's the case. Thus,
1060
we add a single L{ReplayRestoreEvent} as the first element of
1063
if not self._events or type(self._events[0]) != ReplayRestoreEvent:
1064
self._events.insert(0, ReplayRestoreEvent())
1065
return self._events[0]
1068
class OrderedContext(object):
1070
def __init__(self, mocker):
1071
self._mocker = mocker
1073
def __enter__(self):
1076
def __exit__(self, type, value, traceback):
1077
self._mocker.unorder()
1080
class Mocker(MockerBase):
1081
__doc__ = MockerBase.__doc__
1083
# Decorator to add recorders on the standard Mocker class.
1084
recorder = Mocker.add_recorder
1087
# --------------------------------------------------------------------
1092
def __init__(self, mocker, path=None, name=None, spec=None, type=None,
1093
object=None, passthrough=False, patcher=None, count=True):
1094
self.__mocker__ = mocker
1095
self.__mocker_path__ = path or Path(self, object)
1096
self.__mocker_name__ = name
1097
self.__mocker_spec__ = spec
1098
self.__mocker_object__ = object
1099
self.__mocker_passthrough__ = passthrough
1100
self.__mocker_patcher__ = patcher
1101
self.__mocker_replace__ = False
1102
self.__mocker_type__ = type
1103
self.__mocker_count__ = count
1105
def __mocker_act__(self, kind, args=(), kwargs={}, object=None):
1106
if self.__mocker_name__ is None:
1107
self.__mocker_name__ = find_object_name(self, 2)
1108
action = Action(kind, args, kwargs, self.__mocker_path__)
1109
path = self.__mocker_path__ + action
1110
if object is not None:
1111
path.root_object = object
1113
return self.__mocker__.act(path)
1114
except MatchError, exception:
1115
root_mock = path.root_mock
1116
if (path.root_object is not None and
1117
root_mock.__mocker_passthrough__):
1118
return path.execute(path.root_object)
1119
# Reinstantiate to show raise statement on traceback, and
1120
# also to make the traceback shown shorter.
1121
raise MatchError(str(exception))
1122
except AssertionError, e:
1123
lines = str(e).splitlines()
1124
message = [ERROR_PREFIX + "Unmet expectation:", ""]
1125
message.append("=> " + lines.pop(0))
1126
message.extend([" " + line for line in lines])
1128
raise AssertionError(os.linesep.join(message))
1130
def __getattribute__(self, name):
1131
if name.startswith("__mocker_"):
1132
return super(Mock, self).__getattribute__(name)
1133
if name == "__class__":
1134
if self.__mocker__.is_recording() or self.__mocker_type__ is None:
1136
return self.__mocker_type__
1137
if name == "__length_hint__":
1138
# This is used by Python 2.6+ to optimize the allocation
1139
# of arrays in certain cases. Pretend it doesn't exist.
1140
raise AttributeError("No __length_hint__ here!")
1141
return self.__mocker_act__("getattr", (name,))
1143
def __setattr__(self, name, value):
1144
if name.startswith("__mocker_"):
1145
return super(Mock, self).__setattr__(name, value)
1146
return self.__mocker_act__("setattr", (name, value))
1148
def __delattr__(self, name):
1149
return self.__mocker_act__("delattr", (name,))
1151
def __call__(self, *args, **kwargs):
1152
return self.__mocker_act__("call", args, kwargs)
1154
def __contains__(self, value):
1155
return self.__mocker_act__("contains", (value,))
1157
def __getitem__(self, key):
1158
return self.__mocker_act__("getitem", (key,))
1160
def __setitem__(self, key, value):
1161
return self.__mocker_act__("setitem", (key, value))
1163
def __delitem__(self, key):
1164
return self.__mocker_act__("delitem", (key,))
1167
# MatchError is turned on an AttributeError so that list() and
1168
# friends act properly when trying to get length hints on
1169
# something that doesn't offer them.
1171
result = self.__mocker_act__("len")
1172
except MatchError, e:
1173
raise AttributeError(str(e))
1174
if type(result) is Mock:
1178
def __nonzero__(self):
1180
result = self.__mocker_act__("nonzero")
1181
except MatchError, e:
1183
if type(result) is Mock:
1188
# XXX On py3k, when next() becomes __next__(), we'll be able
1189
# to return the mock itself because it will be considered
1190
# an iterator (we'll be mocking __next__ as well, which we
1192
result = self.__mocker_act__("iter")
1193
if type(result) is Mock:
1197
# When adding a new action kind here, also add support for it on
1198
# Action.execute() and Path.__str__().
1201
def find_object_name(obj, depth=0):
1202
"""Try to detect how the object is named on a previous scope."""
1204
frame = sys._getframe(depth+1)
1207
for name, frame_obj in frame.f_locals.iteritems():
1208
if frame_obj is obj:
1210
self = frame.f_locals.get("self")
1211
if self is not None:
1213
items = list(self.__dict__.iteritems())
1217
for name, self_obj in items:
1223
# --------------------------------------------------------------------
1226
class Action(object):
1228
def __init__(self, kind, args, kwargs, path=None):
1231
self.kwargs = kwargs
1233
self._execute_cache = {}
1236
if self.path is None:
1237
return "Action(%r, %r, %r)" % (self.kind, self.args, self.kwargs)
1238
return "Action(%r, %r, %r, %r)" % \
1239
(self.kind, self.args, self.kwargs, self.path)
1241
def __eq__(self, other):
1242
return (self.kind == other.kind and
1243
self.args == other.args and
1244
self.kwargs == other.kwargs)
1246
def __ne__(self, other):
1247
return not self.__eq__(other)
1249
def matches(self, other):
1250
return (self.kind == other.kind and
1251
match_params(self.args, self.kwargs, other.args, other.kwargs))
1253
def execute(self, object):
1254
# This caching scheme may fail if the object gets deallocated before
1255
# the action, as the id might get reused. It's somewhat easy to fix
1256
# that with a weakref callback. For our uses, though, the object
1257
# should never get deallocated before the action itself, so we'll
1258
# just keep it simple.
1259
if id(object) in self._execute_cache:
1260
return self._execute_cache[id(object)]
1261
execute = getattr(object, "__mocker_execute__", None)
1262
if execute is not None:
1263
result = execute(self, object)
1266
if kind == "getattr":
1267
result = getattr(object, self.args[0])
1268
elif kind == "setattr":
1269
result = setattr(object, self.args[0], self.args[1])
1270
elif kind == "delattr":
1271
result = delattr(object, self.args[0])
1272
elif kind == "call":
1273
result = object(*self.args, **self.kwargs)
1274
elif kind == "contains":
1275
result = self.args[0] in object
1276
elif kind == "getitem":
1277
result = object[self.args[0]]
1278
elif kind == "setitem":
1279
result = object[self.args[0]] = self.args[1]
1280
elif kind == "delitem":
1281
del object[self.args[0]]
1284
result = len(object)
1285
elif kind == "nonzero":
1286
result = bool(object)
1287
elif kind == "iter":
1288
result = iter(object)
1290
raise RuntimeError("Don't know how to execute %r kind." % kind)
1291
self._execute_cache[id(object)] = result
1297
def __init__(self, root_mock, root_object=None, actions=()):
1298
self.root_mock = root_mock
1299
self.root_object = root_object
1300
self.actions = tuple(actions)
1301
self.__mocker_replace__ = False
1303
def parent_path(self):
1304
if not self.actions:
1306
return self.actions[-1].path
1307
parent_path = property(parent_path)
1309
def __add__(self, action):
1310
"""Return a new path which includes the given action at the end."""
1311
return self.__class__(self.root_mock, self.root_object,
1312
self.actions + (action,))
1314
def __eq__(self, other):
1315
"""Verify if the two paths are equal.
1317
Two paths are equal if they refer to the same mock object, and
1318
have the actions with equal kind, args and kwargs.
1320
if (self.root_mock is not other.root_mock or
1321
self.root_object is not other.root_object or
1322
len(self.actions) != len(other.actions)):
1324
for action, other_action in zip(self.actions, other.actions):
1325
if action != other_action:
1329
def matches(self, other):
1330
"""Verify if the two paths are equivalent.
1332
Two paths are equal if they refer to the same mock object, and
1333
have the same actions performed on them.
1335
if (self.root_mock is not other.root_mock or
1336
len(self.actions) != len(other.actions)):
1338
for action, other_action in zip(self.actions, other.actions):
1339
if not action.matches(other_action):
1343
def execute(self, object):
1344
"""Execute all actions sequentially on object, and return result.
1346
for action in self.actions:
1347
object = action.execute(object)
1351
"""Transform the path into a nice string such as obj.x.y('z')."""
1352
result = self.root_mock.__mocker_name__ or "<mock>"
1353
for action in self.actions:
1354
if action.kind == "getattr":
1355
result = "%s.%s" % (result, action.args[0])
1356
elif action.kind == "setattr":
1357
result = "%s.%s = %r" % (result, action.args[0], action.args[1])
1358
elif action.kind == "delattr":
1359
result = "del %s.%s" % (result, action.args[0])
1360
elif action.kind == "call":
1361
args = [repr(x) for x in action.args]
1362
items = list(action.kwargs.iteritems())
1365
args.append("%s=%r" % pair)
1366
result = "%s(%s)" % (result, ", ".join(args))
1367
elif action.kind == "contains":
1368
result = "%r in %s" % (action.args[0], result)
1369
elif action.kind == "getitem":
1370
result = "%s[%r]" % (result, action.args[0])
1371
elif action.kind == "setitem":
1372
result = "%s[%r] = %r" % (result, action.args[0],
1374
elif action.kind == "delitem":
1375
result = "del %s[%r]" % (result, action.args[0])
1376
elif action.kind == "len":
1377
result = "len(%s)" % result
1378
elif action.kind == "nonzero":
1379
result = "bool(%s)" % result
1380
elif action.kind == "iter":
1381
result = "iter(%s)" % result
1383
raise RuntimeError("Don't know how to format kind %r" %
1388
class SpecialArgument(object):
1389
"""Base for special arguments for matching parameters."""
1391
def __init__(self, object=None):
1392
self.object = object
1395
if self.object is None:
1396
return self.__class__.__name__
1398
return "%s(%r)" % (self.__class__.__name__, self.object)
1400
def matches(self, other):
1403
def __eq__(self, other):
1404
return type(other) == type(self) and self.object == other.object
1407
class ANY(SpecialArgument):
1408
"""Matches any single argument."""
1413
class ARGS(SpecialArgument):
1414
"""Matches zero or more positional arguments."""
1419
class KWARGS(SpecialArgument):
1420
"""Matches zero or more keyword arguments."""
1425
class IS(SpecialArgument):
1427
def matches(self, other):
1428
return self.object is other
1430
def __eq__(self, other):
1431
return type(other) == type(self) and self.object is other.object
1434
class CONTAINS(SpecialArgument):
1436
def matches(self, other):
1439
except AttributeError:
1443
# If an object can't be iterated, and has no __contains__
1444
# hook, it'd blow up on the test below. We test this in
1445
# advance to prevent catching more errors than we really
1448
return self.object in other
1451
class IN(SpecialArgument):
1453
def matches(self, other):
1454
return other in self.object
1457
class MATCH(SpecialArgument):
1459
def matches(self, other):
1460
return bool(self.object(other))
1462
def __eq__(self, other):
1463
return type(other) == type(self) and self.object is other.object
1466
def match_params(args1, kwargs1, args2, kwargs2):
1467
"""Match the two sets of parameters, considering special parameters."""
1469
has_args = ARGS in args1
1470
has_kwargs = KWARGS in args1
1473
args1 = [arg1 for arg1 in args1 if arg1 is not KWARGS]
1474
elif len(kwargs1) != len(kwargs2):
1477
if not has_args and len(args1) != len(args2):
1480
# Either we have the same number of kwargs, or unknown keywords are
1481
# accepted (KWARGS was used), so check just the ones in kwargs1.
1482
for key, arg1 in kwargs1.iteritems():
1483
if key not in kwargs2:
1486
if isinstance(arg1, SpecialArgument):
1487
if not arg1.matches(arg2):
1492
# Keywords match. Now either we have the same number of
1493
# arguments, or ARGS was used. If ARGS wasn't used, arguments
1494
# must match one-on-one necessarily.
1496
for arg1, arg2 in zip(args1, args2):
1497
if isinstance(arg1, SpecialArgument):
1498
if not arg1.matches(arg2):
1504
# Easy choice. Keywords are matching, and anything on args is accepted.
1505
if (ARGS,) == args1:
1508
# We have something different there. If we don't have positional
1509
# arguments on the original call, it can't match.
1511
# Unless we have just several ARGS (which is bizarre, but..).
1513
if arg1 is not ARGS:
1517
# Ok, all bets are lost. We have to actually do the more expensive
1518
# matching. This is an algorithm based on the idea of the Levenshtein
1519
# Distance between two strings, but heavily hacked for this purpose.
1521
if args1[0] is ARGS:
1526
for i in range(len(args1)):
1528
if args1[i] is ARGS:
1529
for j in range(1, args2l):
1530
last, array[j] = array[j], min(array[j-1], array[j], last)
1532
array[0] = i or int(args1[i] != args2[0])
1533
for j in range(1, args2l):
1534
last, array[j] = array[j], last or int(args1[i] != args2[j])
1542
# --------------------------------------------------------------------
1543
# Event and task base.
1545
class Event(object):
1546
"""Aggregation of tasks that keep track of a recorded action.
1548
An event represents something that may or may not happen while the
1549
mocked environment is running, such as an attribute access, or a
1550
method call. The event is composed of several tasks that are
1551
orchestrated together to create a composed meaning for the event,
1552
including for which actions it should be run, what happens when it
1553
runs, and what's the expectations about the actions run.
1556
def __init__(self, path=None):
1559
self._has_run = False
1561
def add_task(self, task):
1562
"""Add a new task to this taks."""
1563
self._tasks.append(task)
1566
def remove_task(self, task):
1567
self._tasks.remove(task)
1569
def get_tasks(self):
1570
return self._tasks[:]
1572
def matches(self, path):
1573
"""Return true if *all* tasks match the given path."""
1574
for task in self._tasks:
1575
if not task.matches(path):
1577
return bool(self._tasks)
1580
return self._has_run
1582
def may_run(self, path):
1583
"""Verify if any task would certainly raise an error if run.
1585
This will call the C{may_run()} method on each task and return
1586
false if any of them returns false.
1588
for task in self._tasks:
1589
if not task.may_run(path):
1593
def run(self, path):
1594
"""Run all tasks with the given action.
1596
@param path: The path of the expression run.
1598
Running an event means running all of its tasks individually and in
1599
order. An event should only ever be run if all of its tasks claim to
1600
match the given action.
1602
The result of this method will be the last result of a task
1603
which isn't None, or None if they're all None.
1605
self._has_run = True
1608
for task in self._tasks:
1610
task_result = task.run(path)
1611
except AssertionError, e:
1614
raise RuntimeError("Empty error message from %r" % task)
1615
errors.append(error)
1617
if task_result is not None:
1618
result = task_result
1620
message = [str(self.path)]
1621
if str(path) != message[0]:
1622
message.append("- Run: %s" % path)
1623
for error in errors:
1624
lines = error.splitlines()
1625
message.append("- " + lines.pop(0))
1626
message.extend([" " + line for line in lines])
1627
raise AssertionError(os.linesep.join(message))
1630
def satisfied(self):
1631
"""Return true if all tasks are satisfied.
1633
Being satisfied means that there are no unmet expectations.
1635
for task in self._tasks:
1638
except AssertionError:
1643
"""Run verify on all tasks.
1645
The verify method is supposed to raise an AssertionError if the
1646
task has unmet expectations, with a one-line explanation about
1647
why this item is unmet. This method should be safe to be called
1648
multiple times without side effects.
1651
for task in self._tasks:
1654
except AssertionError, e:
1657
raise RuntimeError("Empty error message from %r" % task)
1658
errors.append(error)
1660
message = [str(self.path)]
1661
for error in errors:
1662
lines = error.splitlines()
1663
message.append("- " + lines.pop(0))
1664
message.extend([" " + line for line in lines])
1665
raise AssertionError(os.linesep.join(message))
1668
"""Put all tasks in replay mode."""
1669
self._has_run = False
1670
for task in self._tasks:
1674
"""Restore the state of all tasks."""
1675
for task in self._tasks:
1679
class ReplayRestoreEvent(Event):
1680
"""Helper event for tasks which need replay/restore but shouldn't match."""
1682
def matches(self, path):
1687
"""Element used to track one specific aspect on an event.
1689
A task is responsible for adding any kind of logic to an event.
1690
Examples of that are counting the number of times the event was
1691
made, verifying parameters if any, and so on.
1694
def matches(self, path):
1695
"""Return true if the task is supposed to be run for the given path.
1699
def may_run(self, path):
1700
"""Return false if running this task would certainly raise an error."""
1703
def run(self, path):
1704
"""Perform the task item, considering that the given action happened.
1708
"""Raise AssertionError if expectations for this item are unmet.
1710
The verify method is supposed to raise an AssertionError if the
1711
task has unmet expectations, with a one-line explanation about
1712
why this item is unmet. This method should be safe to be called
1713
multiple times without side effects.
1717
"""Put the task in replay mode.
1719
Any expectations of the task should be reset.
1723
"""Restore any environmental changes made by the task.
1725
Verify should continue to work after this is called.
1729
# --------------------------------------------------------------------
1730
# Task implementations.
1732
class OnRestoreCaller(Task):
1733
"""Call a given callback when restoring."""
1735
def __init__(self, callback):
1736
self._callback = callback
1742
class PathMatcher(Task):
1743
"""Match the action path against a given path."""
1745
def __init__(self, path):
1748
def matches(self, path):
1749
return self.path.matches(path)
1751
def path_matcher_recorder(mocker, event):
1752
event.add_task(PathMatcher(event.path))
1754
Mocker.add_recorder(path_matcher_recorder)
1757
class RunCounter(Task):
1758
"""Task which verifies if the number of runs are within given boundaries.
1761
def __init__(self, min, max=False):
1764
self.max = sys.maxint
1774
def may_run(self, path):
1775
return self._runs < self.max
1777
def run(self, path):
1779
if self._runs > self.max:
1783
if not self.min <= self._runs <= self.max:
1784
if self._runs < self.min:
1785
raise AssertionError("Performed fewer times than expected.")
1786
raise AssertionError("Performed more times than expected.")
1789
class ImplicitRunCounter(RunCounter):
1790
"""RunCounter inserted by default on any event.
1792
This is a way to differentiate explicitly added counters and
1796
def run_counter_recorder(mocker, event):
1797
"""Any event may be repeated once, unless disabled by default."""
1798
if event.path.root_mock.__mocker_count__:
1799
event.add_task(ImplicitRunCounter(1))
1801
Mocker.add_recorder(run_counter_recorder)
1803
def run_counter_removal_recorder(mocker, event):
1805
Events created by getattr actions which lead to other events
1806
may be repeated any number of times. For that, we remove implicit
1807
run counters of any getattr actions leading to the current one.
1809
parent_path = event.path.parent_path
1810
for event in mocker.get_events()[::-1]:
1811
if (event.path is parent_path and
1812
event.path.actions[-1].kind == "getattr"):
1813
for task in event.get_tasks():
1814
if type(task) is ImplicitRunCounter:
1815
event.remove_task(task)
1817
Mocker.add_recorder(run_counter_removal_recorder)
1820
class MockReturner(Task):
1821
"""Return a mock based on the action path."""
1823
def __init__(self, mocker):
1824
self.mocker = mocker
1826
def run(self, path):
1827
return Mock(self.mocker, path)
1829
def mock_returner_recorder(mocker, event):
1830
"""Events that lead to other events must return mock objects."""
1831
parent_path = event.path.parent_path
1832
for event in mocker.get_events():
1833
if event.path is parent_path:
1834
for task in event.get_tasks():
1835
if isinstance(task, MockReturner):
1838
event.add_task(MockReturner(mocker))
1841
Mocker.add_recorder(mock_returner_recorder)
1844
class FunctionRunner(Task):
1845
"""Task that runs a function everything it's run.
1847
Arguments of the last action in the path are passed to the function,
1848
and the function result is also returned.
1851
def __init__(self, func, with_root_object=False):
1853
self._with_root_object = with_root_object
1855
def run(self, path):
1856
action = path.actions[-1]
1857
if self._with_root_object:
1858
return self._func(path.root_object, *action.args, **action.kwargs)
1860
return self._func(*action.args, **action.kwargs)
1863
class PathExecuter(Task):
1864
"""Task that executes a path in the real object, and returns the result."""
1866
def __init__(self, result_callback=None):
1867
self._result_callback = result_callback
1869
def get_result_callback(self):
1870
return self._result_callback
1872
def run(self, path):
1873
result = path.execute(path.root_object)
1874
if self._result_callback is not None:
1875
self._result_callback(result)
1879
class Orderer(Task):
1880
"""Task to establish an order relation between two events.
1882
An orderer task will only match once all its dependencies have
1886
def __init__(self, path):
1889
self._dependencies = []
1897
def may_run(self, path):
1898
for dependency in self._dependencies:
1899
if not dependency.has_run():
1903
def run(self, path):
1904
for dependency in self._dependencies:
1905
if not dependency.has_run():
1906
raise AssertionError("Should be after: %s" % dependency.path)
1909
def add_dependency(self, orderer):
1910
self._dependencies.append(orderer)
1912
def get_dependencies(self):
1913
return self._dependencies
1916
class SpecChecker(Task):
1917
"""Task to check if arguments of the last action conform to a real method.
1920
def __init__(self, method):
1921
self._method = method
1922
self._unsupported = False
1926
self._args, self._varargs, self._varkwargs, self._defaults = \
1927
inspect.getargspec(method)
1929
self._unsupported = True
1931
if self._defaults is None:
1933
if type(method) is type(self.run):
1934
self._args = self._args[1:]
1936
def get_method(self):
1939
def _raise(self, message):
1940
spec = inspect.formatargspec(self._args, self._varargs,
1941
self._varkwargs, self._defaults)
1942
raise AssertionError("Specification is %s%s: %s" %
1943
(self._method.__name__, spec, message))
1946
if not self._method:
1947
raise AssertionError("Method not found in real specification")
1949
def may_run(self, path):
1952
except AssertionError:
1956
def run(self, path):
1957
if not self._method:
1958
raise AssertionError("Method not found in real specification")
1959
if self._unsupported:
1960
return # Can't check it. Happens with builtin functions. :-(
1961
action = path.actions[-1]
1962
obtained_len = len(action.args)
1963
obtained_kwargs = action.kwargs.copy()
1964
nodefaults_len = len(self._args) - len(self._defaults)
1965
for i, name in enumerate(self._args):
1966
if i < obtained_len and name in action.kwargs:
1967
self._raise("%r provided twice" % name)
1968
if (i >= obtained_len and i < nodefaults_len and
1969
name not in action.kwargs):
1970
self._raise("%r not provided" % name)
1971
obtained_kwargs.pop(name, None)
1972
if obtained_len > len(self._args) and not self._varargs:
1973
self._raise("too many args provided")
1974
if obtained_kwargs and not self._varkwargs:
1975
self._raise("unknown kwargs: %s" % ", ".join(obtained_kwargs))
1977
def spec_checker_recorder(mocker, event):
1978
spec = event.path.root_mock.__mocker_spec__
1980
actions = event.path.actions
1981
if len(actions) == 1:
1982
if actions[0].kind == "call":
1983
method = getattr(spec, "__call__", None)
1984
event.add_task(SpecChecker(method))
1985
elif len(actions) == 2:
1986
if actions[0].kind == "getattr" and actions[1].kind == "call":
1987
method = getattr(spec, actions[0].args[0], None)
1988
event.add_task(SpecChecker(method))
1990
Mocker.add_recorder(spec_checker_recorder)
1993
class ProxyReplacer(Task):
1994
"""Task which installs and deinstalls proxy mocks.
1996
This task will replace a real object by a mock in all dictionaries
1997
found in the running interpreter via the garbage collecting system.
2000
def __init__(self, mock):
2002
self.__mocker_replace__ = False
2005
global_replace(self.mock.__mocker_object__, self.mock)
2008
global_replace(self.mock, self.mock.__mocker_object__)
2011
def global_replace(remove, install):
2012
"""Replace object 'remove' with object 'install' on all dictionaries."""
2013
for referrer in gc.get_referrers(remove):
2014
if (type(referrer) is dict and
2015
referrer.get("__mocker_replace__", True)):
2016
for key, value in list(referrer.iteritems()):
2018
referrer[key] = install
2021
class Undefined(object):
2026
Undefined = Undefined()
2029
class Patcher(Task):
2032
super(Patcher, self).__init__()
2033
self._monitored = {} # {kind: {id(object): object}}
2036
def is_monitoring(self, obj, kind):
2037
monitored = self._monitored.get(kind)
2039
if id(obj) in monitored:
2042
if issubclass(cls, type):
2044
bases = set([id(base) for base in cls.__mro__])
2045
bases.intersection_update(monitored)
2049
def monitor(self, obj, kind):
2050
if kind not in self._monitored:
2051
self._monitored[kind] = {}
2052
self._monitored[kind][id(obj)] = obj
2054
def patch_attr(self, obj, attr, value):
2055
original = obj.__dict__.get(attr, Undefined)
2056
self._patched[id(obj), attr] = obj, attr, original
2057
setattr(obj, attr, value)
2059
def get_unpatched_attr(self, obj, attr):
2061
if issubclass(cls, type):
2064
for mro_cls in cls.__mro__:
2065
key = (id(mro_cls), attr)
2066
if key in self._patched:
2067
result = self._patched[key][2]
2068
if result is not Undefined:
2070
elif attr in mro_cls.__dict__:
2071
result = mro_cls.__dict__.get(attr, Undefined)
2073
if isinstance(result, object) and hasattr(type(result), "__get__"):
2076
return result.__get__(obj, cls)
2079
def _get_kind_attr(self, kind):
2080
if kind == "getattr":
2081
return "__getattribute__"
2082
return "__%s__" % kind
2085
for kind in self._monitored:
2086
attr = self._get_kind_attr(kind)
2088
for obj in self._monitored[kind].itervalues():
2090
if issubclass(cls, type):
2094
unpatched = getattr(cls, attr, Undefined)
2095
self.patch_attr(cls, attr,
2096
PatchedMethod(kind, unpatched,
2097
self.is_monitoring))
2098
self.patch_attr(cls, "__mocker_execute__",
2102
for obj, attr, original in self._patched.itervalues():
2103
if original is Undefined:
2106
setattr(obj, attr, original)
2107
self._patched.clear()
2109
def execute(self, action, object):
2110
attr = self._get_kind_attr(action.kind)
2111
unpatched = self.get_unpatched_attr(object, attr)
2113
return unpatched(*action.args, **action.kwargs)
2114
except AttributeError:
2115
type, value, traceback = sys.exc_info()
2116
if action.kind == "getattr":
2117
# The normal behavior of Python is to try __getattribute__,
2118
# and if it raises AttributeError, try __getattr__. We've
2119
# tried the unpatched __getattribute__ above, and we'll now
2122
__getattr__ = unpatched("__getattr__")
2123
except AttributeError:
2126
return __getattr__(*action.args, **action.kwargs)
2127
raise type, value, traceback
2130
class PatchedMethod(object):
2132
def __init__(self, kind, unpatched, is_monitoring):
2134
self._unpatched = unpatched
2135
self._is_monitoring = is_monitoring
2137
def __get__(self, obj, cls=None):
2139
if not self._is_monitoring(object, self._kind):
2140
return self._unpatched.__get__(obj, cls)
2141
def method(*args, **kwargs):
2142
if self._kind == "getattr" and args[0].startswith("__mocker_"):
2143
return self._unpatched.__get__(obj, cls)(args[0])
2144
mock = object.__mocker_mock__
2145
return mock.__mocker_act__(self._kind, args, kwargs, object)
2148
def __call__(self, obj, *args, **kwargs):
2149
# At least with __getattribute__, Python seems to use *both* the
2150
# descriptor API and also call the class attribute directly. It
2151
# looks like an interpreter bug, or at least an undocumented
2153
return self.__get__(obj)(*args, **kwargs)
2156
def patcher_recorder(mocker, event):
2157
mock = event.path.root_mock
2158
if mock.__mocker_patcher__ and len(event.path.actions) == 1:
2159
patcher = mock.__mocker_patcher__
2160
patcher.monitor(mock.__mocker_object__, event.path.actions[0].kind)
2162
Mocker.add_recorder(patcher_recorder)