2 Copyright (c) 2007 Gustavo Niemeyer <gustavo@niemeyer.net>
4 Graceful platform for test doubles in Python (mocks, stubs, fakes, and dummies).
17 if sys
.version_info
< (2, 4):
18 from sets
import Set
as set # pragma: nocover
21 __all__
= ["Mocker", "expect", "IS", "CONTAINS", "IN", "MATCH",
22 "ANY", "ARGS", "KWARGS"]
25 __author__
= "Gustavo Niemeyer <gustavo@niemeyer.net>"
26 __license__
= "PSF License"
27 __version__
= "0.10.1"
30 ERROR_PREFIX
= "[Mocker] "
33 # --------------------------------------------------------------------
36 class MatchError(AssertionError):
37 """Raised when an unknown expression is seen in playback mode."""
40 # --------------------------------------------------------------------
41 # Helper for chained-style calling.
44 """This is a simple helper that allows a different call-style.
46 With this class one can comfortably do chaining of calls to the
47 mocker object responsible by the object being handled. For instance::
49 expect(obj.attr).result(3).count(1, 2)
59 def __init__(self
, mock
, attr
=None):
63 def __getattr__(self
, attr
):
64 return self
.__class
__(self
._mock
, attr
)
66 def __call__(self
, *args
, **kwargs
):
67 getattr(self
._mock
.__mocker
__, self
._attr
)(*args
, **kwargs
)
71 # --------------------------------------------------------------------
72 # Extensions to Python's unittest.
74 class MockerTestCase(unittest
.TestCase
):
75 """unittest.TestCase subclass with Mocker support.
77 @ivar mocker: The mocker instance.
79 This is a convenience only. Mocker may easily be used with the
80 standard C{unittest.TestCase} class if wanted.
82 Test methods have a Mocker instance available on C{self.mocker}.
83 At the end of each test method, expectations of the mocker will
84 be verified, and any requested changes made to the environment
87 In addition to the integration with Mocker, this class provides
88 a few additional helper methods.
93 def __init__(self
, methodName
="runTest"):
94 # So here is the trick: we take the real test method, wrap it on
95 # a function that do the job we have to do, and insert it in the
96 # *instance* dictionary, so that getattr() will return our
97 # replacement rather than the class method.
98 test_method
= getattr(self
, methodName
, None)
99 if test_method
is not None:
100 def test_method_wrapper():
102 result
= test_method()
106 if (self
.mocker
.is_recording() and
107 self
.mocker
.get_events()):
108 raise RuntimeError("Mocker must be put in replay "
109 "mode with self.mocker.replay()")
110 if (hasattr(result
, "addCallback") and
111 hasattr(result
, "addErrback")):
115 result
.addCallback(verify
)
119 # Copy all attributes from the original method..
120 for attr
in dir(test_method
):
121 # .. unless they're present in our wrapper already.
122 if not hasattr(test_method_wrapper
, attr
) or attr
== "__doc__":
123 setattr(test_method_wrapper
, attr
,
124 getattr(test_method
, attr
))
125 setattr(self
, methodName
, test_method_wrapper
)
127 # We could overload run() normally, but other well-known testing
128 # frameworks do it as well, and some of them won't call the super,
129 # which might mean that cleanup wouldn't happen. With that in mind,
130 # we make integration easier by using the following trick.
131 run_method
= self
.run
132 def run_wrapper(*args
, **kwargs
):
134 return run_method(*args
, **kwargs
)
137 self
.run
= run_wrapper
139 self
.mocker
= Mocker()
141 self
.__cleanup
_funcs
= []
142 self
.__cleanup
_paths
= []
144 super(MockerTestCase
, self
).__init
__(methodName
)
147 for path
in self
.__cleanup
_paths
:
148 if os
.path
.isfile(path
):
150 elif os
.path
.isdir(path
):
152 self
.mocker
.restore()
153 for func
, args
, kwargs
in self
.__cleanup
_funcs
:
154 func(*args
, **kwargs
)
156 def addCleanup(self
, func
, *args
, **kwargs
):
157 self
.__cleanup
_funcs
.append((func
, args
, kwargs
))
159 def makeFile(self
, content
=None, suffix
="", prefix
="tmp", basename
=None,
160 dirname
=None, path
=None):
161 """Create a temporary file and return the path to it.
163 @param content: Initial content for the file.
164 @param suffix: Suffix to be given to the file's basename.
165 @param prefix: Prefix to be given to the file's basename.
166 @param basename: Full basename for the file.
167 @param dirname: Put file inside this directory.
169 The file is removed after the test runs.
172 self
.__cleanup
_paths
.append(path
)
173 elif basename
is not None:
175 dirname
= tempfile
.mkdtemp()
176 self
.__cleanup
_paths
.append(dirname
)
177 path
= os
.path
.join(dirname
, basename
)
179 fd
, path
= tempfile
.mkstemp(suffix
, prefix
, dirname
)
180 self
.__cleanup
_paths
.append(path
)
184 if content
is not None:
185 file = open(path
, "w")
190 def makeDir(self
, suffix
="", prefix
="tmp", dirname
=None, path
=None):
191 """Create a temporary directory and return the path to it.
193 @param suffix: Suffix to be given to the file's basename.
194 @param prefix: Prefix to be given to the file's basename.
195 @param dirname: Put directory inside this parent directory.
197 The directory is removed after the test runs.
202 path
= tempfile
.mkdtemp(suffix
, prefix
, dirname
)
203 self
.__cleanup
_paths
.append(path
)
206 def failUnlessIs(self
, first
, second
, msg
=None):
207 """Assert that C{first} is the same object as C{second}."""
208 if first
is not second
:
209 raise self
.failureException(msg
or "%r is not %r" % (first
, second
))
211 def failIfIs(self
, first
, second
, msg
=None):
212 """Assert that C{first} is not the same object as C{second}."""
214 raise self
.failureException(msg
or "%r is %r" % (first
, second
))
216 def failUnlessIn(self
, first
, second
, msg
=None):
217 """Assert that C{first} is contained in C{second}."""
218 if first
not in second
:
219 raise self
.failureException(msg
or "%r not in %r" % (first
, second
))
221 def failUnlessStartsWith(self
, first
, second
, msg
=None):
222 """Assert that C{first} starts with C{second}."""
223 if first
[:len(second
)] != second
:
224 raise self
.failureException(msg
or "%r doesn't start with %r" %
227 def failIfStartsWith(self
, first
, second
, msg
=None):
228 """Assert that C{first} doesn't start with C{second}."""
229 if first
[:len(second
)] == second
:
230 raise self
.failureException(msg
or "%r starts with %r" %
233 def failUnlessEndsWith(self
, first
, second
, msg
=None):
234 """Assert that C{first} starts with C{second}."""
235 if first
[len(first
)-len(second
):] != second
:
236 raise self
.failureException(msg
or "%r doesn't end with %r" %
239 def failIfEndsWith(self
, first
, second
, msg
=None):
240 """Assert that C{first} doesn't start with C{second}."""
241 if first
[len(first
)-len(second
):] == second
:
242 raise self
.failureException(msg
or "%r ends with %r" %
245 def failIfIn(self
, first
, second
, msg
=None):
246 """Assert that C{first} is not contained in C{second}."""
248 raise self
.failureException(msg
or "%r in %r" % (first
, second
))
250 def failUnlessApproximates(self
, first
, second
, tolerance
, msg
=None):
251 """Assert that C{first} is near C{second} by at most C{tolerance}."""
252 if abs(first
- second
) > tolerance
:
253 raise self
.failureException(msg
or "abs(%r - %r) > %r" %
254 (first
, second
, tolerance
))
256 def failIfApproximates(self
, first
, second
, tolerance
, msg
=None):
257 """Assert that C{first} is far from C{second} by at least C{tolerance}.
259 if abs(first
- second
) <= tolerance
:
260 raise self
.failureException(msg
or "abs(%r - %r) <= %r" %
261 (first
, second
, tolerance
))
263 def failUnlessMethodsMatch(self
, first
, second
):
264 """Assert that public methods in C{first} are present in C{second}.
266 This method asserts that all public methods found in C{first} are also
267 present in C{second} and accept the same arguments. C{first} may
268 have its own private methods, though, and may not have all methods
269 found in C{second}. Note that if a private method in C{first} matches
270 the name of one in C{second}, their specification is still compared.
272 This is useful to verify if a fake or stub class have the same API as
273 the real class being simulated.
275 first_methods
= dict(inspect
.getmembers(first
, inspect
.ismethod
))
276 second_methods
= dict(inspect
.getmembers(second
, inspect
.ismethod
))
277 for name
, first_method
in first_methods
.items():
278 first_argspec
= inspect
.getargspec(first_method
)
279 first_formatted
= inspect
.formatargspec(*first_argspec
)
281 second_method
= second_methods
.get(name
)
282 if second_method
is None:
284 continue # First may have its own private methods.
285 raise self
.failureException("%s.%s%s not present in %s" %
286 (first
.__name
__, name
, first_formatted
, second
.__name
__))
288 second_argspec
= inspect
.getargspec(second_method
)
289 if first_argspec
!= second_argspec
:
290 second_formatted
= inspect
.formatargspec(*second_argspec
)
291 raise self
.failureException("%s.%s%s != %s.%s%s" %
292 (first
.__name
__, name
, first_formatted
,
293 second
.__name
__, name
, second_formatted
))
296 assertIs
= failUnlessIs
297 assertIsNot
= failIfIs
298 assertIn
= failUnlessIn
299 assertNotIn
= failIfIn
300 assertStartsWith
= failUnlessStartsWith
301 assertNotStartsWith
= failIfStartsWith
302 assertEndsWith
= failUnlessEndsWith
303 assertNotEndsWith
= failIfEndsWith
304 assertApproximates
= failUnlessApproximates
305 assertNotApproximates
= failIfApproximates
306 assertMethodsMatch
= failUnlessMethodsMatch
308 # The following are missing in Python < 2.4.
309 assertTrue
= unittest
.TestCase
.failUnless
310 assertFalse
= unittest
.TestCase
.failIf
312 # The following is provided for compatibility with Twisted's trial.
313 assertIdentical
= assertIs
314 assertNotIdentical
= assertIsNot
315 failUnlessIdentical
= failUnlessIs
316 failIfIdentical
= failIfIs
319 # --------------------------------------------------------------------
322 class classinstancemethod(object):
324 def __init__(self
, method
):
327 def __get__(self
, obj
, cls
=None):
328 def bound_method(*args
, **kwargs
):
329 return self
.method(cls
, obj
, *args
, **kwargs
)
333 class MockerBase(object):
334 """Controller of mock objects.
336 A mocker instance is used to command recording and replay of
337 expectations on any number of mock objects.
339 Expectations should be expressed for the mock object while in
340 record mode (the initial one) by using the mock object itself,
341 and using the mocker (and/or C{expect()} as a helper) to define
342 additional behavior for each event. For instance::
348 assert mock.hello() == "Hi!"
352 In this short excerpt a mock object is being created, then an
353 expectation of a call to the C{hello()} method was recorded, and
354 when called the method should return the value C{10}. Then, the
355 mocker is put in replay mode, and the expectation is satisfied by
356 calling the C{hello()} method, which indeed returns 10. Finally,
357 a call to the L{restore()} method is performed to undo any needed
358 changes made in the environment, and the L{verify()} method is
359 called to ensure that all defined expectations were met.
361 The same logic can be expressed more elegantly using the
362 C{with mocker:} statement, as follows::
368 assert mock.hello() == "Hi!"
370 Also, the MockerTestCase class, which integrates the mocker on
371 a unittest.TestCase subclass, may be used to reduce the overhead
372 of controlling the mocker. A test could be written as follows::
374 class SampleTest(MockerTestCase):
376 def test_hello(self):
377 mock = self.mocker.mock()
379 self.mocker.result("Hi!")
381 self.assertEquals(mock.hello(), "Hi!")
386 # For convenience only.
389 class __metaclass__(type):
390 def __init__(self
, name
, bases
, dict):
391 # Make independent lists on each subclass, inheriting from parent.
392 self
._recorders
= list(getattr(self
, "_recorders", ()))
395 self
._recorders
= self
._recorders
[:]
397 self
._recording
= True
398 self
._ordering
= False
399 self
._last
_orderer
= None
401 def is_recording(self
):
402 """Return True if in recording mode, False if in replay mode.
404 Recording is the initial state.
406 return self
._recording
409 """Change to replay mode, where recorded events are reproduced.
411 If already in replay mode, the mocker will be restored, with all
412 expectations reset, and then put again in replay mode.
414 An alternative and more comfortable way to replay changes is
415 using the 'with' statement, as follows::
422 The 'with' statement will automatically put mocker in replay
423 mode, and will also verify if all events were correctly reproduced
424 at the end (using L{verify()}), and also restore any changes done
425 in the environment (with L{restore()}).
427 Also check the MockerTestCase class, which integrates the
428 unittest.TestCase class with mocker.
430 if not self
._recording
:
431 for event
in self
._events
:
434 self
._recording
= False
435 for event
in self
._events
:
439 """Restore changes in the environment, and return to recording mode.
441 This should always be called after the test is complete (succeeding
442 or not). There are ways to call this method automatically on
443 completion (e.g. using a C{with mocker:} statement, or using the
444 L{MockerTestCase} class.
446 if not self
._recording
:
447 self
._recording
= True
448 for event
in self
._events
:
452 """Reset the mocker state.
454 This will restore environment changes, if currently in replay
455 mode, and then remove all events previously recorded.
457 if not self
._recording
:
462 def get_events(self
):
463 """Return all recorded events."""
464 return self
._events
[:]
466 def add_event(self
, event
):
469 This method is used internally by the implementation, and
470 shouldn't be needed on normal mocker usage.
472 self
._events
.append(event
)
474 orderer
= event
.add_task(Orderer(event
.path
))
475 if self
._last
_orderer
:
476 orderer
.add_dependency(self
._last
_orderer
)
477 self
._last
_orderer
= orderer
481 """Check if all expectations were met, and raise AssertionError if not.
483 The exception message will include a nice description of which
484 expectations were not met, and why.
487 for event
in self
._events
:
490 except AssertionError, e
:
493 raise RuntimeError("Empty error message from %r"
497 message
= [ERROR_PREFIX
+ "Unmet expectations:", ""]
499 lines
= error
.splitlines()
500 message
.append("=> " + lines
.pop(0))
501 message
.extend([" " + line
for line
in lines
])
503 raise AssertionError(os
.linesep
.join(message
))
505 def mock(self
, spec_and_type
=None, spec
=None, type=None,
506 name
=None, count
=True):
507 """Return a new mock object.
509 @param spec_and_type: Handy positional argument which sets both
511 @param spec: Method calls will be checked for correctness against
513 @param type: If set, the Mock's __class__ attribute will return
514 the given type. This will make C{isinstance()} calls
516 @param name: Name for the mock object, used in the representation of
517 expressions. The name is rarely needed, as it's usually
518 guessed correctly from the variable name used.
519 @param count: If set to false, expressions may be executed any number
520 of times, unless an expectation is explicitly set using
521 the L{count()} method. By default, expressions are
524 if spec_and_type
is not None:
525 spec
= type = spec_and_type
526 return Mock(self
, spec
=spec
, type=type, name
=name
, count
=count
)
528 def proxy(self
, object, spec
=True, type=True, name
=None, count
=True,
530 """Return a new mock object which proxies to the given object.
532 Proxies are useful when only part of the behavior of an object
533 is to be mocked. Unknown expressions may be passed through to
534 the real implementation implicitly (if the C{passthrough} argument
535 is True), or explicitly (using the L{passthrough()} method
538 @param object: Real object to be proxied, and replaced by the mock
539 on replay mode. It may also be an "import path",
540 such as C{"time.time"}, in which case the object
541 will be the C{time} function from the C{time} module.
542 @param spec: Method calls will be checked for correctness against
543 the given object, which may be a class or an instance
544 where attributes will be looked up. Defaults to the
545 the C{object} parameter. May be set to None explicitly,
546 in which case spec checking is disabled. Checks may
547 also be disabled explicitly on a per-event basis with
548 the L{nospec()} method.
549 @param type: If set, the Mock's __class__ attribute will return
550 the given type. This will make C{isinstance()} calls
551 on the object work. Defaults to the type of the
552 C{object} parameter. May be set to None explicitly.
553 @param name: Name for the mock object, used in the representation of
554 expressions. The name is rarely needed, as it's usually
555 guessed correctly from the variable name used.
556 @param count: If set to false, expressions may be executed any number
557 of times, unless an expectation is explicitly set using
558 the L{count()} method. By default, expressions are
560 @param passthrough: If set to False, passthrough of actions on the
561 proxy to the real object will only happen when
562 explicitly requested via the L{passthrough()}
565 if isinstance(object, basestring
):
568 import_stack
= object.split(".")
571 module_path
= ".".join(import_stack
)
573 object = __import__(module_path
, {}, {}, [""])
575 attr_stack
.insert(0, import_stack
.pop())
580 for attr
in attr_stack
:
581 object = getattr(object, attr
)
586 type = __builtin__
.type(object)
587 return Mock(self
, spec
=spec
, type=type, object=object,
588 name
=name
, count
=count
, passthrough
=passthrough
)
590 def replace(self
, object, spec
=True, type=True, name
=None, count
=True,
592 """Create a proxy, and replace the original object with the mock.
594 On replay, the original object will be replaced by the returned
595 proxy in all dictionaries found in the running interpreter via
596 the garbage collecting system. This should cover module
597 namespaces, class namespaces, instance namespaces, and so on.
599 @param object: Real object to be proxied, and replaced by the mock
600 on replay mode. It may also be an "import path",
601 such as C{"time.time"}, in which case the object
602 will be the C{time} function from the C{time} module.
603 @param spec: Method calls will be checked for correctness against
604 the given object, which may be a class or an instance
605 where attributes will be looked up. Defaults to the
606 the C{object} parameter. May be set to None explicitly,
607 in which case spec checking is disabled. Checks may
608 also be disabled explicitly on a per-event basis with
609 the L{nospec()} method.
610 @param type: If set, the Mock's __class__ attribute will return
611 the given type. This will make C{isinstance()} calls
612 on the object work. Defaults to the type of the
613 C{object} parameter. May be set to None explicitly.
614 @param name: Name for the mock object, used in the representation of
615 expressions. The name is rarely needed, as it's usually
616 guessed correctly from the variable name used.
617 @param passthrough: If set to False, passthrough of actions on the
618 proxy to the real object will only happen when
619 explicitly requested via the L{passthrough()}
622 mock
= self
.proxy(object, spec
, type, name
, count
, passthrough
)
623 event
= self
._get
_replay
_restore
_event
()
624 event
.add_task(ProxyReplacer(mock
))
627 def patch(self
, object, spec
=True):
628 """Patch an existing object to reproduce recorded events.
630 @param object: Class or instance to be patched.
631 @param spec: Method calls will be checked for correctness against
632 the given object, which may be a class or an instance
633 where attributes will be looked up. Defaults to the
634 the C{object} parameter. May be set to None explicitly,
635 in which case spec checking is disabled. Checks may
636 also be disabled explicitly on a per-event basis with
637 the L{nospec()} method.
639 The result of this method is still a mock object, which can be
640 used like any other mock object to record events. The difference
641 is that when the mocker is put on replay mode, the *real* object
642 will be modified to behave according to recorded expectations.
644 Patching works in individual instances, and also in classes.
645 When an instance is patched, recorded events will only be
646 considered on this specific instance, and other instances should
647 behave normally. When a class is patched, the reproduction of
648 events will be considered on any instance of this class once
649 created (collectively).
651 Observe that, unlike with proxies which catch only events done
652 through the mock object, *all* accesses to recorded expectations
653 will be considered; even these coming from the object itself
654 (e.g. C{self.hello()} is considered if this method was patched).
655 While this is a very powerful feature, and many times the reason
656 to use patches in the first place, it's important to keep this
659 Patching of the original object only takes place when the mocker
660 is put on replay mode, and the patched object will be restored
661 to its original state once the L{restore()} method is called
662 (explicitly, or implicitly with alternative conventions, such as
663 a C{with mocker:} block, or a MockerTestCase class).
668 event
= self
._get
_replay
_restore
_event
()
669 event
.add_task(patcher
)
670 mock
= Mock(self
, object=object, patcher
=patcher
,
671 passthrough
=True, spec
=spec
)
672 object.__mocker
_mock
__ = mock
676 """This is called by mock objects whenever something happens to them.
678 This method is part of the implementation between the mocker
682 event
= self
.add_event(Event(path
))
683 for recorder
in self
._recorders
:
684 recorder(self
, event
)
685 return Mock(self
, path
)
687 # First run events that may run, then run unsatisfied events, then
688 # ones not previously run. We put the index in the ordering tuple
689 # instead of the actual event because we want a stable sort
690 # (ordering between 2 events is undefined).
691 events
= self
._events
692 order
= [(events
[i
].satisfied()*2 + events
[i
].has_run(), i
)
693 for i
in range(len(events
))]
696 for weight
, i
in order
:
698 if event
.matches(path
):
699 if event
.may_run(path
):
700 return event
.run(path
)
701 elif postponed
is None:
703 if postponed
is not None:
704 return postponed
.run(path
)
705 raise MatchError(ERROR_PREFIX
+ "Unexpected expression: %s" % path
)
707 def get_recorders(cls
, self
):
708 """Return recorders associated with this mocker class or instance.
710 This method may be called on mocker instances and also on mocker
711 classes. See the L{add_recorder()} method for more information.
713 return (self
or cls
)._recorders
[:]
714 get_recorders
= classinstancemethod(get_recorders
)
716 def add_recorder(cls
, self
, recorder
):
717 """Add a recorder to this mocker class or instance.
719 @param recorder: Callable accepting C{(mocker, event)} as parameters.
721 This is part of the implementation of mocker.
723 All registered recorders are called for translating events that
724 happen during recording into expectations to be met once the state
725 is switched to replay mode.
727 This method may be called on mocker instances and also on mocker
728 classes. When called on a class, the recorder will be used by
729 all instances, and also inherited on subclassing. When called on
730 instances, the recorder is added only to the given instance.
732 (self
or cls
)._recorders
.append(recorder
)
734 add_recorder
= classinstancemethod(add_recorder
)
736 def remove_recorder(cls
, self
, recorder
):
737 """Remove the given recorder from this mocker class or instance.
739 This method may be called on mocker classes and also on mocker
740 instances. See the L{add_recorder()} method for more information.
742 (self
or cls
)._recorders
.remove(recorder
)
743 remove_recorder
= classinstancemethod(remove_recorder
)
745 def result(self
, value
):
746 """Make the last recorded event return the given value on replay.
748 @param value: Object to be returned when the event is replayed.
750 self
.call(lambda *args
, **kwargs
: value
)
752 def generate(self
, sequence
):
753 """Last recorded event will return a generator with the given sequence.
755 @param sequence: Sequence of values to be generated.
757 def generate(*args
, **kwargs
):
758 for value
in sequence
:
762 def throw(self
, exception
):
763 """Make the last recorded event raise the given exception on replay.
765 @param exception: Class or instance of exception to be raised.
767 def raise_exception(*args
, **kwargs
):
769 self
.call(raise_exception
)
771 def call(self
, func
):
772 """Make the last recorded event cause the given function to be called.
774 @param func: Function to be called.
776 The result of the function will be used as the event result.
778 self
._events
[-1].add_task(FunctionRunner(func
))
780 def count(self
, min, max=False):
781 """Last recorded event must be replayed between min and max times.
783 @param min: Minimum number of times that the event must happen.
784 @param max: Maximum number of times that the event must happen. If
785 not given, it defaults to the same value of the C{min}
786 parameter. If set to None, there is no upper limit, and
787 the expectation is met as long as it happens at least
790 event
= self
._events
[-1]
791 for task
in event
.get_tasks():
792 if isinstance(task
, RunCounter
):
793 event
.remove_task(task
)
794 event
.add_task(RunCounter(min, max))
796 def is_ordering(self
):
797 """Return true if all events are being ordered.
799 See the L{order()} method.
801 return self
._ordering
804 """Disable the ordered mode.
806 See the L{order()} method for more information.
808 self
._ordering
= False
809 self
._last
_orderer
= None
811 def order(self
, *path_holders
):
812 """Create an expectation of order between two or more events.
814 @param path_holders: Objects returned as the result of recorded events.
816 By default, mocker won't force events to happen precisely in
817 the order they were recorded. Calling this method will change
818 this behavior so that events will only match if reproduced in
821 There are two ways in which this method may be used. Which one
822 is used in a given occasion depends only on convenience.
824 If no arguments are passed, the mocker will be put in a mode where
825 all the recorded events following the method call will only be met
826 if they happen in order. When that's used, the mocker may be put
827 back in unordered mode by calling the L{unorder()} method, or by
828 using a 'with' block, like so::
830 with mocker.ordered():
833 In this case, only expressions in <record events> will be ordered,
834 and the mocker will be back in unordered mode after the 'with' block.
836 The second way to use it is by specifying precisely which events
837 should be ordered. As an example::
843 mocker.order(expr1, expr2, expr3)
845 This method of ordering only works when the expression returns
848 Also check the L{after()} and L{before()} methods, which are
849 alternative ways to perform this.
852 self
._ordering
= True
853 return OrderedContext(self
)
856 for path_holder
in path_holders
:
857 if type(path_holder
) is Path
:
860 path
= path_holder
.__mocker
_path
__
861 for event
in self
._events
:
862 if event
.path
is path
:
863 for task
in event
.get_tasks():
864 if isinstance(task
, Orderer
):
868 orderer
= Orderer(path
)
869 event
.add_task(orderer
)
871 orderer
.add_dependency(last_orderer
)
872 last_orderer
= orderer
875 def after(self
, *path_holders
):
876 """Last recorded event must happen after events referred to.
878 @param path_holders: Objects returned as the result of recorded events
879 which should happen before the last recorded event
881 As an example, the idiom::
883 expect(mock.x).after(mock.y, mock.z)
885 is an alternative way to say::
890 mocker.order(expr_y, expr_x)
891 mocker.order(expr_z, expr_x)
893 See L{order()} for more information.
895 last_path
= self
._events
[-1].path
896 for path_holder
in path_holders
:
897 self
.order(path_holder
, last_path
)
899 def before(self
, *path_holders
):
900 """Last recorded event must happen before events referred to.
902 @param path_holders: Objects returned as the result of recorded events
903 which should happen after the last recorded event
905 As an example, the idiom::
907 expect(mock.x).before(mock.y, mock.z)
909 is an alternative way to say::
914 mocker.order(expr_x, expr_y)
915 mocker.order(expr_x, expr_z)
917 See L{order()} for more information.
919 last_path
= self
._events
[-1].path
920 for path_holder
in path_holders
:
921 self
.order(last_path
, path_holder
)
924 """Don't check method specification of real object on last event.
926 By default, when using a mock created as the result of a call to
927 L{proxy()}, L{replace()}, and C{patch()}, or when passing the spec
928 attribute to the L{mock()} method, method calls on the given object
929 are checked for correctness against the specification of the real
930 object (or the explicitly provided spec).
932 This method will disable that check specifically for the last
935 event
= self
._events
[-1]
936 for task
in event
.get_tasks():
937 if isinstance(task
, SpecChecker
):
938 event
.remove_task(task
)
940 def passthrough(self
, result_callback
=None):
941 """Make the last recorded event run on the real object once seen.
943 @param result_callback: If given, this function will be called with
944 the result of the *real* method call as the only argument.
946 This can only be used on proxies, as returned by the L{proxy()}
947 and L{replace()} methods, or on mocks representing patched objects,
948 as returned by the L{patch()} method.
950 event
= self
._events
[-1]
951 if event
.path
.root_object
is None:
952 raise TypeError("Mock object isn't a proxy")
953 event
.add_task(PathExecuter(result_callback
))
956 """Enter in a 'with' context. This will run replay()."""
960 def __exit__(self
, type, value
, traceback
):
961 """Exit from a 'with' context.
963 This will run restore() at all times, but will only run verify()
964 if the 'with' block itself hasn't raised an exception. Exceptions
965 in that block are never swallowed.
972 def _get_replay_restore_event(self
):
973 """Return unique L{ReplayRestoreEvent}, creating if needed.
975 Some tasks only want to replay/restore. When that's the case,
976 they shouldn't act on other events during replay. Also, they
977 can all be put in a single event when that's the case. Thus,
978 we add a single L{ReplayRestoreEvent} as the first element of
981 if not self
._events
or type(self
._events
[0]) != ReplayRestoreEvent
:
982 self
._events
.insert(0, ReplayRestoreEvent())
983 return self
._events
[0]
986 class OrderedContext(object):
988 def __init__(self
, mocker
):
989 self
._mocker
= mocker
994 def __exit__(self
, type, value
, traceback
):
995 self
._mocker
.unorder()
998 class Mocker(MockerBase
):
999 __doc__
= MockerBase
.__doc
__
1001 # Decorator to add recorders on the standard Mocker class.
1002 recorder
= Mocker
.add_recorder
1005 # --------------------------------------------------------------------
1010 def __init__(self
, mocker
, path
=None, name
=None, spec
=None, type=None,
1011 object=None, passthrough
=False, patcher
=None, count
=True):
1012 self
.__mocker
__ = mocker
1013 self
.__mocker
_path
__ = path
or Path(self
, object)
1014 self
.__mocker
_name
__ = name
1015 self
.__mocker
_spec
__ = spec
1016 self
.__mocker
_object
__ = object
1017 self
.__mocker
_passthrough
__ = passthrough
1018 self
.__mocker
_patcher
__ = patcher
1019 self
.__mocker
_replace
__ = False
1020 self
.__mocker
_type
__ = type
1021 self
.__mocker
_count
__ = count
1023 def __mocker_act__(self
, kind
, args
=(), kwargs
={}, object=None):
1024 if self
.__mocker
_name
__ is None:
1025 self
.__mocker
_name
__ = find_object_name(self
, 2)
1026 action
= Action(kind
, args
, kwargs
, self
.__mocker
_path
__)
1027 path
= self
.__mocker
_path
__ + action
1028 if object is not None:
1029 path
.root_object
= object
1031 return self
.__mocker
__.act(path
)
1032 except MatchError
, exception
:
1033 root_mock
= path
.root_mock
1034 if (path
.root_object
is not None and
1035 root_mock
.__mocker
_passthrough
__):
1036 return path
.execute(path
.root_object
)
1037 # Reinstantiate to show raise statement on traceback, and
1038 # also to make the traceback shown shorter.
1039 raise MatchError(str(exception
))
1040 except AssertionError, e
:
1041 lines
= str(e
).splitlines()
1042 message
= [ERROR_PREFIX
+ "Unmet expectation:", ""]
1043 message
.append("=> " + lines
.pop(0))
1044 message
.extend([" " + line
for line
in lines
])
1046 raise AssertionError(os
.linesep
.join(message
))
1048 def __getattribute__(self
, name
):
1049 if name
.startswith("__mocker_"):
1050 return super(Mock
, self
).__getattribute
__(name
)
1051 if name
== "__class__":
1052 if self
.__mocker
__.is_recording() or self
.__mocker
_type
__ is None:
1054 return self
.__mocker
_type
__
1055 return self
.__mocker
_act
__("getattr", (name
,))
1057 def __setattr__(self
, name
, value
):
1058 if name
.startswith("__mocker_"):
1059 return super(Mock
, self
).__setattr
__(name
, value
)
1060 return self
.__mocker
_act
__("setattr", (name
, value
))
1062 def __delattr__(self
, name
):
1063 return self
.__mocker
_act
__("delattr", (name
,))
1065 def __call__(self
, *args
, **kwargs
):
1066 return self
.__mocker
_act
__("call", args
, kwargs
)
1068 def __contains__(self
, value
):
1069 return self
.__mocker
_act
__("contains", (value
,))
1071 def __getitem__(self
, key
):
1072 return self
.__mocker
_act
__("getitem", (key
,))
1074 def __setitem__(self
, key
, value
):
1075 return self
.__mocker
_act
__("setitem", (key
, value
))
1077 def __delitem__(self
, key
):
1078 return self
.__mocker
_act
__("delitem", (key
,))
1081 # MatchError is turned on an AttributeError so that list() and
1082 # friends act properly when trying to get length hints on
1083 # something that doesn't offer them.
1085 result
= self
.__mocker
_act
__("len")
1086 except MatchError
, e
:
1087 raise AttributeError(str(e
))
1088 if type(result
) is Mock
:
1092 def __nonzero__(self
):
1094 return self
.__mocker
_act
__("nonzero")
1095 except MatchError
, e
:
1099 # XXX On py3k, when next() becomes __next__(), we'll be able
1100 # to return the mock itself because it will be considered
1101 # an iterator (we'll be mocking __next__ as well, which we
1103 result
= self
.__mocker
_act
__("iter")
1104 if type(result
) is Mock
:
1108 # When adding a new action kind here, also add support for it on
1109 # Action.execute() and Path.__str__().
1112 def find_object_name(obj
, depth
=0):
1113 """Try to detect how the object is named on a previous scope."""
1115 frame
= sys
._getframe
(depth
+1)
1118 for name
, frame_obj
in frame
.f_locals
.iteritems():
1119 if frame_obj
is obj
:
1121 self
= frame
.f_locals
.get("self")
1122 if self
is not None:
1124 items
= list(self
.__dict
__.iteritems())
1128 for name
, self_obj
in items
:
1134 # --------------------------------------------------------------------
1137 class Action(object):
1139 def __init__(self
, kind
, args
, kwargs
, path
=None):
1142 self
.kwargs
= kwargs
1144 self
._execute
_cache
= {}
1147 if self
.path
is None:
1148 return "Action(%r, %r, %r)" % (self
.kind
, self
.args
, self
.kwargs
)
1149 return "Action(%r, %r, %r, %r)" % \
1150 (self
.kind
, self
.args
, self
.kwargs
, self
.path
)
1152 def __eq__(self
, other
):
1153 return (self
.kind
== other
.kind
and
1154 self
.args
== other
.args
and
1155 self
.kwargs
== other
.kwargs
)
1157 def __ne__(self
, other
):
1158 return not self
.__eq
__(other
)
1160 def matches(self
, other
):
1161 return (self
.kind
== other
.kind
and
1162 match_params(self
.args
, self
.kwargs
, other
.args
, other
.kwargs
))
1164 def execute(self
, object):
1165 # This caching scheme may fail if the object gets deallocated before
1166 # the action, as the id might get reused. It's somewhat easy to fix
1167 # that with a weakref callback. For our uses, though, the object
1168 # should never get deallocated before the action itself, so we'll
1169 # just keep it simple.
1170 if id(object) in self
._execute
_cache
:
1171 return self
._execute
_cache
[id(object)]
1172 execute
= getattr(object, "__mocker_execute__", None)
1173 if execute
is not None:
1174 result
= execute(self
, object)
1177 if kind
== "getattr":
1178 result
= getattr(object, self
.args
[0])
1179 elif kind
== "setattr":
1180 result
= setattr(object, self
.args
[0], self
.args
[1])
1181 elif kind
== "delattr":
1182 result
= delattr(object, self
.args
[0])
1183 elif kind
== "call":
1184 result
= object(*self
.args
, **self
.kwargs
)
1185 elif kind
== "contains":
1186 result
= self
.args
[0] in object
1187 elif kind
== "getitem":
1188 result
= object[self
.args
[0]]
1189 elif kind
== "setitem":
1190 result
= object[self
.args
[0]] = self
.args
[1]
1191 elif kind
== "delitem":
1192 del object[self
.args
[0]]
1195 result
= len(object)
1196 elif kind
== "nonzero":
1197 result
= bool(object)
1198 elif kind
== "iter":
1199 result
= iter(object)
1201 raise RuntimeError("Don't know how to execute %r kind." % kind
)
1202 self
._execute
_cache
[id(object)] = result
1208 def __init__(self
, root_mock
, root_object
=None, actions
=()):
1209 self
.root_mock
= root_mock
1210 self
.root_object
= root_object
1211 self
.actions
= tuple(actions
)
1212 self
.__mocker
_replace
__ = False
1214 def parent_path(self
):
1215 if not self
.actions
:
1217 return self
.actions
[-1].path
1218 parent_path
= property(parent_path
)
1220 def __add__(self
, action
):
1221 """Return a new path which includes the given action at the end."""
1222 return self
.__class
__(self
.root_mock
, self
.root_object
,
1223 self
.actions
+ (action
,))
1225 def __eq__(self
, other
):
1226 """Verify if the two paths are equal.
1228 Two paths are equal if they refer to the same mock object, and
1229 have the actions with equal kind, args and kwargs.
1231 if (self
.root_mock
is not other
.root_mock
or
1232 self
.root_object
is not other
.root_object
or
1233 len(self
.actions
) != len(other
.actions
)):
1235 for action
, other_action
in zip(self
.actions
, other
.actions
):
1236 if action
!= other_action
:
1240 def matches(self
, other
):
1241 """Verify if the two paths are equivalent.
1243 Two paths are equal if they refer to the same mock object, and
1244 have the same actions performed on them.
1246 if (self
.root_mock
is not other
.root_mock
or
1247 len(self
.actions
) != len(other
.actions
)):
1249 for action
, other_action
in zip(self
.actions
, other
.actions
):
1250 if not action
.matches(other_action
):
1254 def execute(self
, object):
1255 """Execute all actions sequentially on object, and return result.
1257 for action
in self
.actions
:
1258 object = action
.execute(object)
1262 """Transform the path into a nice string such as obj.x.y('z')."""
1263 result
= self
.root_mock
.__mocker
_name
__ or "<mock>"
1264 for action
in self
.actions
:
1265 if action
.kind
== "getattr":
1266 result
= "%s.%s" % (result
, action
.args
[0])
1267 elif action
.kind
== "setattr":
1268 result
= "%s.%s = %r" % (result
, action
.args
[0], action
.args
[1])
1269 elif action
.kind
== "delattr":
1270 result
= "del %s.%s" % (result
, action
.args
[0])
1271 elif action
.kind
== "call":
1272 args
= [repr(x
) for x
in action
.args
]
1273 items
= list(action
.kwargs
.iteritems())
1276 args
.append("%s=%r" % pair
)
1277 result
= "%s(%s)" % (result
, ", ".join(args
))
1278 elif action
.kind
== "contains":
1279 result
= "%r in %s" % (action
.args
[0], result
)
1280 elif action
.kind
== "getitem":
1281 result
= "%s[%r]" % (result
, action
.args
[0])
1282 elif action
.kind
== "setitem":
1283 result
= "%s[%r] = %r" % (result
, action
.args
[0],
1285 elif action
.kind
== "delitem":
1286 result
= "del %s[%r]" % (result
, action
.args
[0])
1287 elif action
.kind
== "len":
1288 result
= "len(%s)" % result
1289 elif action
.kind
== "nonzero":
1290 result
= "bool(%s)" % result
1291 elif action
.kind
== "iter":
1292 result
= "iter(%s)" % result
1294 raise RuntimeError("Don't know how to format kind %r" %
1299 class SpecialArgument(object):
1300 """Base for special arguments for matching parameters."""
1302 def __init__(self
, object=None):
1303 self
.object = object
1306 if self
.object is None:
1307 return self
.__class
__.__name
__
1309 return "%s(%r)" % (self
.__class
__.__name
__, self
.object)
1311 def matches(self
, other
):
1314 def __eq__(self
, other
):
1315 return type(other
) == type(self
) and self
.object == other
.object
1318 class ANY(SpecialArgument
):
1319 """Matches any single argument."""
1324 class ARGS(SpecialArgument
):
1325 """Matches zero or more positional arguments."""
1330 class KWARGS(SpecialArgument
):
1331 """Matches zero or more keyword arguments."""
1336 class IS(SpecialArgument
):
1338 def matches(self
, other
):
1339 return self
.object is other
1341 def __eq__(self
, other
):
1342 return type(other
) == type(self
) and self
.object is other
.object
1345 class CONTAINS(SpecialArgument
):
1347 def matches(self
, other
):
1350 except AttributeError:
1354 # If an object can't be iterated, and has no __contains__
1355 # hook, it'd blow up on the test below. We test this in
1356 # advance to prevent catching more errors than we really
1359 return self
.object in other
1362 class IN(SpecialArgument
):
1364 def matches(self
, other
):
1365 return other
in self
.object
1368 class MATCH(SpecialArgument
):
1370 def matches(self
, other
):
1371 return bool(self
.object(other
))
1373 def __eq__(self
, other
):
1374 return type(other
) == type(self
) and self
.object is other
.object
1377 def match_params(args1
, kwargs1
, args2
, kwargs2
):
1378 """Match the two sets of parameters, considering special parameters."""
1380 has_args
= ARGS
in args1
1381 has_kwargs
= KWARGS
in args1
1384 args1
= [arg1
for arg1
in args1
if arg1
is not KWARGS
]
1385 elif len(kwargs1
) != len(kwargs2
):
1388 if not has_args
and len(args1
) != len(args2
):
1391 # Either we have the same number of kwargs, or unknown keywords are
1392 # accepted (KWARGS was used), so check just the ones in kwargs1.
1393 for key
, arg1
in kwargs1
.iteritems():
1394 if key
not in kwargs2
:
1397 if isinstance(arg1
, SpecialArgument
):
1398 if not arg1
.matches(arg2
):
1403 # Keywords match. Now either we have the same number of
1404 # arguments, or ARGS was used. If ARGS wasn't used, arguments
1405 # must match one-on-one necessarily.
1407 for arg1
, arg2
in zip(args1
, args2
):
1408 if isinstance(arg1
, SpecialArgument
):
1409 if not arg1
.matches(arg2
):
1415 # Easy choice. Keywords are matching, and anything on args is accepted.
1416 if (ARGS
,) == args1
:
1419 # We have something different there. If we don't have positional
1420 # arguments on the original call, it can't match.
1422 # Unless we have just several ARGS (which is bizarre, but..).
1424 if arg1
is not ARGS
:
1428 # Ok, all bets are lost. We have to actually do the more expensive
1429 # matching. This is an algorithm based on the idea of the Levenshtein
1430 # Distance between two strings, but heavily hacked for this purpose.
1432 if args1
[0] is ARGS
:
1437 for i
in range(len(args1
)):
1439 if args1
[i
] is ARGS
:
1440 for j
in range(1, args2l
):
1441 last
, array
[j
] = array
[j
], min(array
[j
-1], array
[j
], last
)
1443 array
[0] = i
or int(args1
[i
] != args2
[0])
1444 for j
in range(1, args2l
):
1445 last
, array
[j
] = array
[j
], last
or int(args1
[i
] != args2
[j
])
1453 # --------------------------------------------------------------------
1454 # Event and task base.
1456 class Event(object):
1457 """Aggregation of tasks that keep track of a recorded action.
1459 An event represents something that may or may not happen while the
1460 mocked environment is running, such as an attribute access, or a
1461 method call. The event is composed of several tasks that are
1462 orchestrated together to create a composed meaning for the event,
1463 including for which actions it should be run, what happens when it
1464 runs, and what's the expectations about the actions run.
1467 def __init__(self
, path
=None):
1470 self
._has
_run
= False
1472 def add_task(self
, task
):
1473 """Add a new task to this taks."""
1474 self
._tasks
.append(task
)
1477 def remove_task(self
, task
):
1478 self
._tasks
.remove(task
)
1480 def get_tasks(self
):
1481 return self
._tasks
[:]
1483 def matches(self
, path
):
1484 """Return true if *all* tasks match the given path."""
1485 for task
in self
._tasks
:
1486 if not task
.matches(path
):
1488 return bool(self
._tasks
)
1491 return self
._has
_run
1493 def may_run(self
, path
):
1494 """Verify if any task would certainly raise an error if run.
1496 This will call the C{may_run()} method on each task and return
1497 false if any of them returns false.
1499 for task
in self
._tasks
:
1500 if not task
.may_run(path
):
1504 def run(self
, path
):
1505 """Run all tasks with the given action.
1507 @param path: The path of the expression run.
1509 Running an event means running all of its tasks individually and in
1510 order. An event should only ever be run if all of its tasks claim to
1511 match the given action.
1513 The result of this method will be the last result of a task
1514 which isn't None, or None if they're all None.
1516 self
._has
_run
= True
1519 for task
in self
._tasks
:
1521 task_result
= task
.run(path
)
1522 except AssertionError, e
:
1525 raise RuntimeError("Empty error message from %r" % task
)
1526 errors
.append(error
)
1528 if task_result
is not None:
1529 result
= task_result
1531 message
= [str(self
.path
)]
1532 if str(path
) != message
[0]:
1533 message
.append("- Run: %s" % path
)
1534 for error
in errors
:
1535 lines
= error
.splitlines()
1536 message
.append("- " + lines
.pop(0))
1537 message
.extend([" " + line
for line
in lines
])
1538 raise AssertionError(os
.linesep
.join(message
))
1541 def satisfied(self
):
1542 """Return true if all tasks are satisfied.
1544 Being satisfied means that there are no unmet expectations.
1546 for task
in self
._tasks
:
1549 except AssertionError:
1554 """Run verify on all tasks.
1556 The verify method is supposed to raise an AssertionError if the
1557 task has unmet expectations, with a one-line explanation about
1558 why this item is unmet. This method should be safe to be called
1559 multiple times without side effects.
1562 for task
in self
._tasks
:
1565 except AssertionError, e
:
1568 raise RuntimeError("Empty error message from %r" % task
)
1569 errors
.append(error
)
1571 message
= [str(self
.path
)]
1572 for error
in errors
:
1573 lines
= error
.splitlines()
1574 message
.append("- " + lines
.pop(0))
1575 message
.extend([" " + line
for line
in lines
])
1576 raise AssertionError(os
.linesep
.join(message
))
1579 """Put all tasks in replay mode."""
1580 self
._has
_run
= False
1581 for task
in self
._tasks
:
1585 """Restore the state of all tasks."""
1586 for task
in self
._tasks
:
1590 class ReplayRestoreEvent(Event
):
1591 """Helper event for tasks which need replay/restore but shouldn't match."""
1593 def matches(self
, path
):
1598 """Element used to track one specific aspect on an event.
1600 A task is responsible for adding any kind of logic to an event.
1601 Examples of that are counting the number of times the event was
1602 made, verifying parameters if any, and so on.
1605 def matches(self
, path
):
1606 """Return true if the task is supposed to be run for the given path.
1610 def may_run(self
, path
):
1611 """Return false if running this task would certainly raise an error."""
1614 def run(self
, path
):
1615 """Perform the task item, considering that the given action happened.
1619 """Raise AssertionError if expectations for this item are unmet.
1621 The verify method is supposed to raise an AssertionError if the
1622 task has unmet expectations, with a one-line explanation about
1623 why this item is unmet. This method should be safe to be called
1624 multiple times without side effects.
1628 """Put the task in replay mode.
1630 Any expectations of the task should be reset.
1634 """Restore any environmental changes made by the task.
1636 Verify should continue to work after this is called.
1640 # --------------------------------------------------------------------
1641 # Task implementations.
1643 class OnRestoreCaller(Task
):
1644 """Call a given callback when restoring."""
1646 def __init__(self
, callback
):
1647 self
._callback
= callback
1653 class PathMatcher(Task
):
1654 """Match the action path against a given path."""
1656 def __init__(self
, path
):
1659 def matches(self
, path
):
1660 return self
.path
.matches(path
)
1662 def path_matcher_recorder(mocker
, event
):
1663 event
.add_task(PathMatcher(event
.path
))
1665 Mocker
.add_recorder(path_matcher_recorder
)
1668 class RunCounter(Task
):
1669 """Task which verifies if the number of runs are within given boundaries.
1672 def __init__(self
, min, max=False):
1675 self
.max = sys
.maxint
1685 def may_run(self
, path
):
1686 return self
._runs
< self
.max
1688 def run(self
, path
):
1690 if self
._runs
> self
.max:
1694 if not self
.min <= self
._runs
<= self
.max:
1695 if self
._runs
< self
.min:
1696 raise AssertionError("Performed fewer times than expected.")
1697 raise AssertionError("Performed more times than expected.")
1700 class ImplicitRunCounter(RunCounter
):
1701 """RunCounter inserted by default on any event.
1703 This is a way to differentiate explicitly added counters and
1707 def run_counter_recorder(mocker
, event
):
1708 """Any event may be repeated once, unless disabled by default."""
1709 if event
.path
.root_mock
.__mocker
_count
__:
1710 event
.add_task(ImplicitRunCounter(1))
1712 Mocker
.add_recorder(run_counter_recorder
)
1714 def run_counter_removal_recorder(mocker
, event
):
1716 Events created by getattr actions which lead to other events
1717 may be repeated any number of times. For that, we remove implicit
1718 run counters of any getattr actions leading to the current one.
1720 parent_path
= event
.path
.parent_path
1721 for event
in mocker
.get_events()[::-1]:
1722 if (event
.path
is parent_path
and
1723 event
.path
.actions
[-1].kind
== "getattr"):
1724 for task
in event
.get_tasks():
1725 if type(task
) is ImplicitRunCounter
:
1726 event
.remove_task(task
)
1728 Mocker
.add_recorder(run_counter_removal_recorder
)
1731 class MockReturner(Task
):
1732 """Return a mock based on the action path."""
1734 def __init__(self
, mocker
):
1735 self
.mocker
= mocker
1737 def run(self
, path
):
1738 return Mock(self
.mocker
, path
)
1740 def mock_returner_recorder(mocker
, event
):
1741 """Events that lead to other events must return mock objects."""
1742 parent_path
= event
.path
.parent_path
1743 for event
in mocker
.get_events():
1744 if event
.path
is parent_path
:
1745 for task
in event
.get_tasks():
1746 if isinstance(task
, MockReturner
):
1749 event
.add_task(MockReturner(mocker
))
1752 Mocker
.add_recorder(mock_returner_recorder
)
1755 class FunctionRunner(Task
):
1756 """Task that runs a function everything it's run.
1758 Arguments of the last action in the path are passed to the function,
1759 and the function result is also returned.
1762 def __init__(self
, func
):
1765 def run(self
, path
):
1766 action
= path
.actions
[-1]
1767 return self
._func
(*action
.args
, **action
.kwargs
)
1770 class PathExecuter(Task
):
1771 """Task that executes a path in the real object, and returns the result."""
1773 def __init__(self
, result_callback
=None):
1774 self
._result
_callback
= result_callback
1776 def get_result_callback(self
):
1777 return self
._result
_callback
1779 def run(self
, path
):
1780 result
= path
.execute(path
.root_object
)
1781 if self
._result
_callback
is not None:
1782 self
._result
_callback
(result
)
1786 class Orderer(Task
):
1787 """Task to establish an order relation between two events.
1789 An orderer task will only match once all its dependencies have
1793 def __init__(self
, path
):
1796 self
._dependencies
= []
1804 def may_run(self
, path
):
1805 for dependency
in self
._dependencies
:
1806 if not dependency
.has_run():
1810 def run(self
, path
):
1811 for dependency
in self
._dependencies
:
1812 if not dependency
.has_run():
1813 raise AssertionError("Should be after: %s" % dependency
.path
)
1816 def add_dependency(self
, orderer
):
1817 self
._dependencies
.append(orderer
)
1819 def get_dependencies(self
):
1820 return self
._dependencies
1823 class SpecChecker(Task
):
1824 """Task to check if arguments of the last action conform to a real method.
1827 def __init__(self
, method
):
1828 self
._method
= method
1829 self
._unsupported
= False
1833 self
._args
, self
._varargs
, self
._varkwargs
, self
._defaults
= \
1834 inspect
.getargspec(method
)
1836 self
._unsupported
= True
1838 if self
._defaults
is None:
1840 if type(method
) is type(self
.run
):
1841 self
._args
= self
._args
[1:]
1843 def get_method(self
):
1846 def _raise(self
, message
):
1847 spec
= inspect
.formatargspec(self
._args
, self
._varargs
,
1848 self
._varkwargs
, self
._defaults
)
1849 raise AssertionError("Specification is %s%s: %s" %
1850 (self
._method
.__name
__, spec
, message
))
1853 if not self
._method
:
1854 raise AssertionError("Method not found in real specification")
1856 def may_run(self
, path
):
1859 except AssertionError:
1863 def run(self
, path
):
1864 if not self
._method
:
1865 raise AssertionError("Method not found in real specification")
1866 if self
._unsupported
:
1867 return # Can't check it. Happens with builtin functions. :-(
1868 action
= path
.actions
[-1]
1869 obtained_len
= len(action
.args
)
1870 obtained_kwargs
= action
.kwargs
.copy()
1871 nodefaults_len
= len(self
._args
) - len(self
._defaults
)
1872 for i
, name
in enumerate(self
._args
):
1873 if i
< obtained_len
and name
in action
.kwargs
:
1874 self
._raise
("%r provided twice" % name
)
1875 if (i
>= obtained_len
and i
< nodefaults_len
and
1876 name
not in action
.kwargs
):
1877 self
._raise
("%r not provided" % name
)
1878 obtained_kwargs
.pop(name
, None)
1879 if obtained_len
> len(self
._args
) and not self
._varargs
:
1880 self
._raise
("too many args provided")
1881 if obtained_kwargs
and not self
._varkwargs
:
1882 self
._raise
("unknown kwargs: %s" % ", ".join(obtained_kwargs
))
1884 def spec_checker_recorder(mocker
, event
):
1885 spec
= event
.path
.root_mock
.__mocker
_spec
__
1887 actions
= event
.path
.actions
1888 if len(actions
) == 1:
1889 if actions
[0].kind
== "call":
1890 method
= getattr(spec
, "__call__", None)
1891 event
.add_task(SpecChecker(method
))
1892 elif len(actions
) == 2:
1893 if actions
[0].kind
== "getattr" and actions
[1].kind
== "call":
1894 method
= getattr(spec
, actions
[0].args
[0], None)
1895 event
.add_task(SpecChecker(method
))
1897 Mocker
.add_recorder(spec_checker_recorder
)
1900 class ProxyReplacer(Task
):
1901 """Task which installs and deinstalls proxy mocks.
1903 This task will replace a real object by a mock in all dictionaries
1904 found in the running interpreter via the garbage collecting system.
1907 def __init__(self
, mock
):
1909 self
.__mocker
_replace
__ = False
1912 global_replace(self
.mock
.__mocker
_object
__, self
.mock
)
1915 global_replace(self
.mock
, self
.mock
.__mocker
_object
__)
1918 def global_replace(remove
, install
):
1919 """Replace object 'remove' with object 'install' on all dictionaries."""
1920 for referrer
in gc
.get_referrers(remove
):
1921 if (type(referrer
) is dict and
1922 referrer
.get("__mocker_replace__", True)):
1923 for key
, value
in referrer
.items():
1925 referrer
[key
] = install
1928 class Undefined(object):
1933 Undefined
= Undefined()
1936 class Patcher(Task
):
1939 super(Patcher
, self
).__init
__()
1940 self
._monitored
= {} # {kind: {id(object): object}}
1943 def is_monitoring(self
, obj
, kind
):
1944 monitored
= self
._monitored
.get(kind
)
1946 if id(obj
) in monitored
:
1949 if issubclass(cls
, type):
1951 bases
= set([id(base
) for base
in cls
.__mro
__])
1952 bases
.intersection_update(monitored
)
1956 def monitor(self
, obj
, kind
):
1957 if kind
not in self
._monitored
:
1958 self
._monitored
[kind
] = {}
1959 self
._monitored
[kind
][id(obj
)] = obj
1961 def patch_attr(self
, obj
, attr
, value
):
1962 original
= obj
.__dict
__.get(attr
, Undefined
)
1963 self
._patched
[id(obj
), attr
] = obj
, attr
, original
1964 setattr(obj
, attr
, value
)
1966 def get_unpatched_attr(self
, obj
, attr
):
1968 if issubclass(cls
, type):
1971 for mro_cls
in cls
.__mro
__:
1972 key
= (id(mro_cls
), attr
)
1973 if key
in self
._patched
:
1974 result
= self
._patched
[key
][2]
1975 if result
is not Undefined
:
1977 elif attr
in mro_cls
.__dict
__:
1978 result
= mro_cls
.__dict
__.get(attr
, Undefined
)
1980 if isinstance(result
, object) and hasattr(type(result
), "__get__"):
1983 return result
.__get
__(obj
, cls
)
1986 def _get_kind_attr(self
, kind
):
1987 if kind
== "getattr":
1988 return "__getattribute__"
1989 return "__%s__" % kind
1992 for kind
in self
._monitored
:
1993 attr
= self
._get
_kind
_attr
(kind
)
1995 for obj
in self
._monitored
[kind
].itervalues():
1997 if issubclass(cls
, type):
2001 unpatched
= getattr(cls
, attr
, Undefined
)
2002 self
.patch_attr(cls
, attr
,
2003 PatchedMethod(kind
, unpatched
,
2004 self
.is_monitoring
))
2005 self
.patch_attr(cls
, "__mocker_execute__",
2009 for obj
, attr
, original
in self
._patched
.itervalues():
2010 if original
is Undefined
:
2013 setattr(obj
, attr
, original
)
2014 self
._patched
.clear()
2016 def execute(self
, action
, object):
2017 attr
= self
._get
_kind
_attr
(action
.kind
)
2018 unpatched
= self
.get_unpatched_attr(object, attr
)
2020 return unpatched(*action
.args
, **action
.kwargs
)
2021 except AttributeError:
2022 if action
.kind
== "getattr":
2023 # The normal behavior of Python is to try __getattribute__,
2024 # and if it raises AttributeError, try __getattr__. We've
2025 # tried the unpatched __getattribute__ above, and we'll now
2028 __getattr__
= unpatched("__getattr__")
2029 except AttributeError:
2032 return __getattr__(*action
.args
, **action
.kwargs
)
2036 class PatchedMethod(object):
2038 def __init__(self
, kind
, unpatched
, is_monitoring
):
2040 self
._unpatched
= unpatched
2041 self
._is
_monitoring
= is_monitoring
2043 def __get__(self
, obj
, cls
=None):
2045 if not self
._is
_monitoring
(object, self
._kind
):
2046 return self
._unpatched
.__get
__(obj
, cls
)
2047 def method(*args
, **kwargs
):
2048 if self
._kind
== "getattr" and args
[0].startswith("__mocker_"):
2049 return self
._unpatched
.__get
__(obj
, cls
)(args
[0])
2050 mock
= object.__mocker
_mock
__
2051 return mock
.__mocker
_act
__(self
._kind
, args
, kwargs
, object)
2054 def __call__(self
, obj
, *args
, **kwargs
):
2055 # At least with __getattribute__, Python seems to use *both* the
2056 # descriptor API and also call the class attribute directly. It
2057 # looks like an interpreter bug, or at least an undocumented
2059 return self
.__get
__(obj
)(*args
, **kwargs
)
2062 def patcher_recorder(mocker
, event
):
2063 mock
= event
.path
.root_mock
2064 if mock
.__mocker
_patcher
__ and len(event
.path
.actions
) == 1:
2065 patcher
= mock
.__mocker
_patcher
__
2066 patcher
.monitor(mock
.__mocker
_object
__, event
.path
.actions
[0].kind
)
2068 Mocker
.add_recorder(patcher_recorder
)