commit 1dbb7befdbd10169a35e27977a0736a9dc9465d0
Author: Sean Robinson <seankrobinson(a)gmail.com>
Date: Sat Dec 22 04:29:46 2012 -0700
Handle keyword arguments with mocking.return_for_args()
Allow a structured way to match keyword arguments to be included in the
mapping keys for return_for_args(). This changes the API for
return_for_args to require tuples as the mapping keys.
Signed-off-by: Sean Robinson <seankrobinson(a)gmail.com>
---
test/mocking.py | 34 +++++++++++++++++++++++++++++-----
test/unit/tutorial.py | 4 ++--
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/test/mocking.py b/test/mocking.py
index fa9e71f..697fd0f 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -210,15 +210,39 @@ def return_for_args(args_to_return_value, default = None):
'argument => return value' mapping. Otherwise, a default function
is called with the arguments.
- :param dict args_to_return_value: mapping of arguments to the value we should provide
+ The mapped argument is a tuple (not a list) of parameters to a function (or
+ method). Positional arguments must be in the order used to call the mocked
+ function and keyword arguments must be strings of the form 'k=v' in
+ alphabetical order. Some examples:
+
+ ::
+
+ Mocked functions can return different types depending on input:
+
+ mocking.mock("get_answer", mocking.return_for_args({
+ ("breakfast_menu",): "spam",
+ ("lunch_menu",): "eggs and spam",
+ (42,): ["life", "universe", "everything"],
+ })
+
+ mocking.mock("align_text", {
+ ("Stem", "alignment=left", "size=10"): "Stem ",
+ ("Stem", "alignment=center", "size=10"): " Stem ",
+ ("Stem", "alignment=right", "size=10"): " Stem",
+ })
+
+ :param dict,tuple args_to_return_value: mapping of arguments to the value we should provide
:param functor default: returns the value of this function if the args don't match something that we have, we raise a ValueError by default
"""
- def _return_value(*args):
+ def _return_value(*args, **kwargs):
# strip off the 'self' for mock clases
if args and 'MockClass' in str(type(args[0])):
- args = args[1:] if len(args) > 2 else args[1]
+ args = args[1:] if len(args) > 2 else [args[1]]
+ if kwargs:
+ args.extend(['='.join((str(k),str(kwargs[k]))) for k in sorted(kwargs.keys())])
+ args = tuple(args)
if args in args_to_return_value:
return args_to_return_value[args]
elif default is None:
@@ -275,7 +299,7 @@ def mock(target, mock_call, target_module=None):
target_function = target.__name__
MOCK_STATE[mocking_id] = (target_module, target_function, target)
- mock_wrapper = lambda *args: mock_call(*args)
+ mock_wrapper = lambda *args, **kwargs: mock_call(*args, **kwargs)
mock_wrapper.__dict__["mock_id"] = mocking_id
# mocks the function with this wrapper
@@ -323,7 +347,7 @@ def mock_method(target_class, method_name, mock_call):
mocking_id = MOCK_ID.next()
MOCK_STATE[mocking_id] = (target_class, method_name, target_method)
- mock_wrapper = lambda *args: mock_call(*args)
+ mock_wrapper = lambda *args, **kwargs: mock_call(*args, **kwargs)
setattr(mock_wrapper, "mock_id", mocking_id)
# mocks the function with this wrapper
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index bb50e11..343258b 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -19,8 +19,8 @@ class TestTutorial(unittest.TestCase):
'authenticate': mocking.no_op(),
'close': mocking.no_op(),
'get_info': mocking.return_for_args({
- 'traffic/read': '1234',
- 'traffic/written': '5678',
+ ('traffic/read',): '1234',
+ ('traffic/written',): '5678',
}),
})