Reference: aspectlib.test
¶
This module aims to be a lightweight and flexible alternative to the popular mock framework and more.
aspectlib.test.record |
Factory or decorator (depending if func is initially given). |
aspectlib.test.mock |
Factory for a decorator that makes the function return a given return_value. |
aspectlib.test.Story |
This a simple yet flexible tool that can do “capture-replay mocking” or “test doubles” [1]. |
aspectlib.test.Replay |
Object implementing the replay transaction. |
-
aspectlib.test.
record
(func=None, recurse_lock_factory=<function allocate_lock>, **options)[source]¶ Factory or decorator (depending if func is initially given).
Parameters: - callback (list) – An a callable that is to be called with
instance, function, args, kwargs
. - calls (list) – An object where the Call objects are appended. If not given and
callback
is not specified then a new list object will be created. - iscalled (bool) – If
True
the func will be called. (default:False
) - extended (bool) – If
True
the func’s__name__
will also be included in the call list. (default:False
) - results (bool) – If
True
the results (and exceptions) will also be included in the call list. (default:False
)
Returns: A wrapper that records all calls made to func. The history is available as a
call
property. If access to the function is too hard then you need to specify the history manually.Example
>>> @record ... def a(x, y, a, b): ... pass >>> a(1, 2, 3, b='c') >>> a.calls [Call(self=None, args=(1, 2, 3), kwargs={'b': 'c'})]
Or, with your own history list:
>>> calls = [] >>> @record(calls=calls) ... def a(x, y, a, b): ... pass >>> a(1, 2, 3, b='c') >>> a.calls [Call(self=None, args=(1, 2, 3), kwargs={'b': 'c'})] >>> calls is a.calls True
Changed in version 0.9.0: Renamed history option to calls. Renamed call option to iscalled. Added callback option. Added extended option.
- callback (list) – An a callable that is to be called with
-
aspectlib.test.
mock
(return_value, call=False)[source]¶ Factory for a decorator that makes the function return a given return_value.
Parameters: - return_value – Value to return from the wrapper.
- call (bool) – If
True
, call the decorated function. (default:False
)
Returns: A decorator.
-
class
aspectlib.test.
Story
(*args, **kwargs)[source]¶ This a simple yet flexible tool that can do “capture-replay mocking” or “test doubles” [1]. It leverages
aspectlib
’s powerfulweaver
.Parameters: - target (same as for
aspectlib.weave
) – Targets to weave in the story/replay transactions. - subclasses (bool) – If
True
, subclasses of target are weaved. Only available for classes - aliases (bool) – If
True
, aliases of target are replaced. - lazy (bool) – If
True
only target’s__init__
method is patched, the rest of the methods are patched after__init__
is called. Only available for classes. - methods (list or regex or string) – Methods from target to patch. Only available for classes
The
Story
allows some testing patterns that are hard to do with other tools:- Proxied mocks: partially mock objects and modules so they are called normally if the request is unknown.
- Stubs: completely mock objects and modules. Raise errors if the request is unknown.
The
Story
works in two of transactions:The story: You describe what calls you want to mocked. Initially you don’t need to write this. Example:
>>> import mymod >>> with Story(mymod) as story: ... mymod.func('some arg') == 'some result' ... mymod.func('bad arg') ** ValueError("can't use this")
The replay: You run the code uses the interfaces mocked in the story. The
replay
always starts from a story instance.
Changed in version 0.9.0: Added in.
[1] (1, 2) http://www.martinfowler.com/bliki/TestDouble.html -
replay
(**options)[source]¶ Parameters: - proxy (bool) – If
True
then unexpected uses are allowed (will use the real functions) but they are collected for later use. Default:True
. - strict (bool) – If
True
then anAssertionError
is raised when there were unexpected calls or there were missing calls (specified in the story but not called). Default:True
. - dump (bool) – If
True
then the unexpected/missing calls will be printed (tosys.stdout
). Default:True
.
Returns: A
aspectlib.test.Replay
object.Example
>>> import mymod >>> with Story(mymod) as story: ... mymod.func('some arg') == 'some result' ... mymod.func('other arg') == 'other result' >>> with story.replay(strict=False): ... print(mymod.func('some arg')) ... mymod.func('bogus arg') some result Got bogus arg in the real code! STORY/REPLAY DIFF: --- expected... +++ actual... @@ -1,2 +1,2 @@ mymod.func('some arg') == 'some result' # returns -mymod.func('other arg') == 'other result' # returns +mymod.func('bogus arg') == None # returns ACTUAL: mymod.func('some arg') == 'some result' # returns mymod.func('bogus arg') == None # returns
- proxy (bool) – If
- target (same as for
-
class
aspectlib.test.
Replay
(?)[source]¶ Object implementing the replay transaction.
This object should be created by
Story
’sreplay
method.-
diff
¶ Returns a pretty text representation of the unexpected and missing calls.
Most of the time you don’t need to directly use this. This is useful when you run the replay in
strict=False
mode and want to do custom assertions.
-
missing
¶ Returns a pretty text representation of just the missing calls.
-
unexpected
¶ Returns a pretty text representation of just the unexpected calls.
The output should be usable directly in the story (just copy-paste it). Example:
>>> import mymod >>> with Story(mymod) as story: ... pass >>> with story.replay(strict=False, dump=False) as replay: ... mymod.func('some arg') ... try: ... mymod.badfunc() ... except ValueError as exc: ... print(exc) Got some arg in the real code! boom! >>> print(replay.unexpected) mymod.func('some arg') == None # returns mymod.badfunc() ** ValueError('boom!',) # raises
We can just take the output and paste in the story:
>>> import mymod >>> with Story(mymod) as story: ... mymod.func('some arg') == None # returns ... mymod.badfunc() ** ValueError('boom!') # raises >>> with story.replay(): ... mymod.func('some arg') ... try: ... mymod.badfunc() ... except ValueError as exc: ... print(exc) boom!
-